Skip to content

Commit d969e2f

Browse files
authored
Feature/improve open api generation (#196)
* Add open api improvement * Add new condition for open api generation * Update generate-open-api.component.ts * Add e2e tests * Update generate-open-api.cy.ts * Add error message when resource path clash with properteis * Add documentation for resource path * Fix cypress e2e tests and change the interceptor for openApi generation * Add documentation link to open api generation with resource path * Fix property matching
1 parent 1fb04a6 commit d969e2f

File tree

22 files changed

+794
-172
lines changed

22 files changed

+794
-172
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
resourceId:
2+
name: resourceId
3+
in: path
4+
description: An example resource Id.
5+
required: true
6+
schema:
7+
type: string

core/apps/ame-e2e/src/integration/editor/generation.cy.ts

Lines changed: 0 additions & 68 deletions
This file was deleted.
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/* eslint-disable cypress/no-unnecessary-waiting */
2+
/*
3+
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
4+
*
5+
* See the AUTHORS file(s) distributed with this work for
6+
* additional information regarding authorship.
7+
*
8+
* This Source Code Form is subject to the terms of the Mozilla Public
9+
* License, v. 2.0. If a copy of the MPL was not distributed with this
10+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
11+
*
12+
* SPDX-License-Identifier: MPL-2.0
13+
*/
14+
15+
/// <reference types="Cypress" />
16+
17+
import {
18+
GENERATION_accordionTitle,
19+
GENERATION_activateResourcePathCheckbox,
20+
GENERATION_removeUploadFile,
21+
GENERATION_resourcePathInput,
22+
GENERATION_resourcePathPatternError,
23+
GENERATION_resourcePathRequiredError,
24+
GENERATION_resourcePathTitle,
25+
GENERATION_tbBaseUrlInput,
26+
GENERATION_tbBaseUrlInputError,
27+
GENERATION_tbGenerateOpenApiButton,
28+
GENERATION_tbOutputButton,
29+
GENERATION_tbOutputButton_JSON,
30+
GENERATION_tbOutputButton_YAML,
31+
GENERATION_uploadContent,
32+
GENERATION_uploadContentFileInput,
33+
GENERATION_uploadFileRequireError,
34+
GENERATION_uploadTitle,
35+
} from '../../support/constants';
36+
37+
describe('Test generation and download of open api specification', () => {
38+
it('Can generate valid JSON Open Api Specification', () => {
39+
cy.visitDefault();
40+
cy.startModelling()
41+
.then(() => cy.openGenerationOpenApiSpec().wait(500))
42+
.then(() => cy.get(GENERATION_tbOutputButton).click())
43+
.then(() => cy.get(GENERATION_tbOutputButton_JSON).click())
44+
.then(() => cy.get(GENERATION_tbBaseUrlInput).focus().clear().blur())
45+
.then(() =>
46+
cy.get(GENERATION_tbBaseUrlInputError).should('exist').should('be.visible').should('contain.text', 'Please add a valid url'),
47+
)
48+
.then(() => cy.get(GENERATION_tbBaseUrlInput).focus().type('https://example.com').blur())
49+
.then(() => cy.get(GENERATION_tbGenerateOpenApiButton).click().wait(5000))
50+
.then(() => cy.fixture('cypress/downloads/en-open-api.json'));
51+
});
52+
53+
it('Can generate valid JSON Open Api Specification with resource path', () => {
54+
cy.visitDefault();
55+
cy.startModelling()
56+
.then(() => cy.openGenerationOpenApiSpec().wait(500))
57+
.then(() => cy.get(GENERATION_tbOutputButton).click())
58+
.then(() => cy.get(GENERATION_tbOutputButton_JSON).click())
59+
.then(() => cy.get(GENERATION_resourcePathTitle).should('not.exist'))
60+
.then(() => cy.get(GENERATION_activateResourcePathCheckbox).click())
61+
.then(() =>
62+
cy
63+
.get(GENERATION_resourcePathTitle)
64+
.should('exist')
65+
.should('be.visible')
66+
.should('contain.text', 'Resource Path - The resource path for the Aspect API endpoints'),
67+
)
68+
.then(() => cy.get(GENERATION_resourcePathInput).should('exist').should('be.visible').focus().clear().blur())
69+
.then(() =>
70+
cy
71+
.get(GENERATION_resourcePathRequiredError)
72+
.should('exist')
73+
.should('be.visible')
74+
.should('contain.text', 'Resource path is required'),
75+
)
76+
.then(() => checkResourcePath())
77+
.then(() => cy.get(GENERATION_uploadTitle).should('exist').should('be.visible').should('contain.text', 'Upload JSON File'))
78+
.then(() => cy.get(GENERATION_uploadContent).should('exist').should('be.visible'))
79+
.then(() =>
80+
cy
81+
.get(GENERATION_uploadFileRequireError)
82+
.should('exist')
83+
.should('be.visible')
84+
.should('contain.text', 'JSON file is required - a variable has been defined in the resource path.'),
85+
)
86+
.then(() => cy.get(GENERATION_uploadContentFileInput).attachFile('valid-json.json'))
87+
.then(() => cy.get(GENERATION_uploadContent).should('not.exist'))
88+
.then(() => cy.get(GENERATION_accordionTitle).should('exist').should('be.visible').should('contain.text', 'Properties'))
89+
.then(() => cy.get(GENERATION_tbGenerateOpenApiButton).click().wait(5000))
90+
.then(() => cy.fixture('cypress/downloads/en-open-api.json'));
91+
});
92+
93+
it('Can generate and download valid YAML Open Api Specification', () => {
94+
cy.visitDefault();
95+
cy.startModelling()
96+
.then(() => cy.openGenerationOpenApiSpec().wait(500))
97+
.then(() => cy.get(GENERATION_tbOutputButton).click())
98+
.then(() => cy.get(GENERATION_tbOutputButton_YAML).click())
99+
.then(() => cy.get(GENERATION_tbBaseUrlInput).focus().clear().blur())
100+
.then(() =>
101+
cy.get(GENERATION_tbBaseUrlInputError).should('exist').should('be.visible').should('contain.text', 'Please add a valid url'),
102+
)
103+
.then(() => cy.get(GENERATION_tbBaseUrlInput).focus().type('https://example.com').blur())
104+
.then(() => cy.get(GENERATION_tbGenerateOpenApiButton).click({force: true}).wait(5000))
105+
.then(() => cy.fixture('cypress/downloads/en-open-api.yaml'));
106+
});
107+
108+
it('Can generate valid YAML Open Api Specification with resource path', () => {
109+
cy.visitDefault();
110+
cy.startModelling()
111+
.then(() => cy.openGenerationOpenApiSpec().wait(500))
112+
.then(() => cy.get(GENERATION_resourcePathTitle).should('not.exist'))
113+
.then(() => cy.get(GENERATION_activateResourcePathCheckbox).click())
114+
.then(() =>
115+
cy
116+
.get(GENERATION_resourcePathTitle)
117+
.should('exist')
118+
.should('be.visible')
119+
.should('contain.text', 'Resource Path - The resource path for the Aspect API endpoints'),
120+
)
121+
.then(() => cy.get(GENERATION_resourcePathInput).should('exist').should('be.visible').focus().clear().blur())
122+
.then(() =>
123+
cy
124+
.get(GENERATION_resourcePathRequiredError)
125+
.should('exist')
126+
.should('be.visible')
127+
.should('contain.text', 'Resource path is required'),
128+
)
129+
.then(() => checkResourcePath())
130+
.then(() => cy.get(GENERATION_uploadTitle).should('exist').should('be.visible').should('contain.text', 'Upload YAML File'))
131+
.then(() => cy.get(GENERATION_uploadContent).should('exist').should('be.visible'))
132+
.then(() =>
133+
cy
134+
.get(GENERATION_uploadFileRequireError)
135+
.should('exist')
136+
.should('be.visible')
137+
.should('contain.text', 'YAML file is required - a variable has been defined in the resource path.'),
138+
)
139+
.then(() => cy.get(GENERATION_uploadContentFileInput).attachFile('valid-yml.yml'))
140+
.then(() => cy.get(GENERATION_uploadContent).should('not.exist'))
141+
.then(() => cy.get(GENERATION_accordionTitle).should('exist').should('be.visible').should('contain.text', 'Properties'))
142+
.then(() => cy.get(GENERATION_tbGenerateOpenApiButton).click().wait(5000))
143+
.then(() => cy.fixture('cypress/downloads/en-open-api.yaml'));
144+
});
145+
146+
it('Test some generate variations', () => {
147+
cy.visitDefault();
148+
cy.startModelling()
149+
.then(() => cy.openGenerationOpenApiSpec().wait(500))
150+
.then(() => cy.get(GENERATION_resourcePathTitle).should('not.exist'))
151+
.then(() => {
152+
cy.get(GENERATION_activateResourcePathCheckbox).click();
153+
cy.get(GENERATION_resourcePathTitle)
154+
.should('exist')
155+
.should('be.visible')
156+
.should('contain.text', 'Resource Path - The resource path for the Aspect API endpoints');
157+
cy.get(GENERATION_resourcePathInput).should('exist').should('be.visible').scrollIntoView();
158+
cy.get(GENERATION_uploadTitle).should('exist').should('be.visible').should('contain.text', 'Upload YAML File');
159+
cy.get(GENERATION_uploadContent).should('exist').should('be.visible');
160+
cy.get(GENERATION_uploadFileRequireError)
161+
.should('exist')
162+
.should('be.visible')
163+
.should('contain.text', 'YAML file is required - a variable has been defined in the resource path.');
164+
cy.get(GENERATION_uploadContentFileInput).attachFile('valid-yml.yml');
165+
cy.get(GENERATION_uploadContent).should('not.exist');
166+
cy.get(GENERATION_accordionTitle).should('exist').should('be.visible').should('contain.text', 'Properties');
167+
cy.get(GENERATION_tbGenerateOpenApiButton).should('be.enabled');
168+
})
169+
.then(() => {
170+
cy.get(GENERATION_removeUploadFile).click({force: true});
171+
cy.get(GENERATION_uploadContent).should('exist').should('be.visible');
172+
cy.get(GENERATION_accordionTitle).should('not.exist');
173+
})
174+
.then(() => {
175+
cy.get(GENERATION_uploadContentFileInput).attachFile('valid-yml.yml');
176+
cy.get(GENERATION_tbOutputButton).click();
177+
cy.get(GENERATION_tbOutputButton_JSON).click();
178+
cy.get(GENERATION_uploadContent).should('exist').should('be.visible');
179+
cy.get(GENERATION_accordionTitle).should('not.exist');
180+
})
181+
.then(() => {
182+
cy.get(GENERATION_uploadContentFileInput).attachFile('valid-json.json');
183+
cy.get(GENERATION_uploadContent).should('not.exist');
184+
cy.get(GENERATION_accordionTitle).should('exist').should('be.visible');
185+
cy.get(GENERATION_tbGenerateOpenApiButton).should('be.enabled');
186+
})
187+
.then(() => {
188+
cy.get(GENERATION_activateResourcePathCheckbox).click();
189+
cy.get(GENERATION_uploadContent).should('not.exist');
190+
cy.get(GENERATION_accordionTitle).should('not.exist');
191+
cy.get(GENERATION_tbGenerateOpenApiButton).should('be.enabled');
192+
});
193+
});
194+
195+
function checkResourcePath(): void {
196+
cy.get(GENERATION_resourcePathInput).focus().type('/').blur();
197+
cy.get(GENERATION_resourcePathPatternError).should('not.exist');
198+
cy.get(GENERATION_resourcePathInput).focus().clear().type('//').blur();
199+
cy.get(GENERATION_resourcePathPatternError).should('exist').should('be.visible').should('contain.text', 'Pattern is not matching');
200+
cy.get(GENERATION_resourcePathInput).focus().clear().type('resource').blur();
201+
cy.get(GENERATION_resourcePathPatternError).should('exist').should('be.visible').should('contain.text', 'Pattern is not matching');
202+
cy.get(GENERATION_resourcePathInput).focus().clear().type('/resource').blur();
203+
cy.get(GENERATION_resourcePathPatternError).should('not.exist');
204+
cy.get(GENERATION_resourcePathInput).focus().clear().type('/resource/{{').blur();
205+
cy.get(GENERATION_resourcePathPatternError).should('exist').should('be.visible').should('contain.text', 'Pattern is not matching');
206+
cy.get(GENERATION_resourcePathInput).focus().clear().type('/resource/}}').blur();
207+
cy.get(GENERATION_resourcePathPatternError).should('exist').should('be.visible').should('contain.text', 'Pattern is not matching');
208+
cy.get(GENERATION_resourcePathInput).focus().clear().type('/resource/{}').blur();
209+
cy.get(GENERATION_resourcePathPatternError).should('not.exist');
210+
cy.get(GENERATION_resourcePathInput).focus().clear().type('/resource/{resourceId}', {parseSpecialCharSequences: false}).blur();
211+
cy.get(GENERATION_resourcePathPatternError).should('not.exist');
212+
}
213+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* eslint-disable cypress/no-unnecessary-waiting */
2+
/*
3+
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
4+
*
5+
* See the AUTHORS file(s) distributed with this work for
6+
* additional information regarding authorship.
7+
*
8+
* This Source Code Form is subject to the terms of the Mozilla Public
9+
* License, v. 2.0. If a copy of the MPL was not distributed with this
10+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
11+
*
12+
* SPDX-License-Identifier: MPL-2.0
13+
*/
14+
15+
/// <reference types="Cypress" />
16+
17+
import {GENERATION_tbDownloadDoc} from '../../support/constants';
18+
19+
describe('Test generation and download of Aspect Model documentation', () => {
20+
it('Can generate and download valid Aspect Model documentation', () => {
21+
cy.visitDefault();
22+
cy.startModelling()
23+
.then(() => cy.openGenerationDocumentation().wait(500))
24+
.then(() => cy.get(GENERATION_tbDownloadDoc).click({force: true}).wait(5000))
25+
.then(() => cy.fixture('cypress/downloads/AspectDefault-documentation.html'));
26+
});
27+
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* eslint-disable cypress/no-unnecessary-waiting */
2+
/*
3+
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
4+
*
5+
* See the AUTHORS file(s) distributed with this work for
6+
* additional information regarding authorship.
7+
*
8+
* This Source Code Form is subject to the terms of the Mozilla Public
9+
* License, v. 2.0. If a copy of the MPL was not distributed with this
10+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
11+
*
12+
* SPDX-License-Identifier: MPL-2.0
13+
*/
14+
15+
/// <reference types="Cypress" />
16+
17+
import {GENERATION_downloadFileButton} from '../../support/constants';
18+
19+
describe('Test generation and download of Json payload/schema', () => {
20+
it('Can generate and download valid Json payload', () => {
21+
cy.visitDefault();
22+
cy.startModelling()
23+
.then(() => cy.openGenerationJsonSample().wait(500))
24+
.then(() => cy.get(GENERATION_downloadFileButton).click({force: true}).wait(5000))
25+
.then(() => cy.fixture('cypress/downloads/AspectDefault-sample.json'));
26+
});
27+
28+
it('Can generate and download valid Json schema', () => {
29+
cy.visitDefault();
30+
cy.startModelling()
31+
.then(() => cy.openGenerationJsonSchema().wait(500))
32+
.then(() => cy.get(GENERATION_downloadFileButton).click({force: true}).wait(5000))
33+
.then(() => cy.fixture('cypress/downloads/AspectDefault-schema.json'));
34+
});
35+
});

core/apps/ame-e2e/src/support/commands.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {FileHandlingService, GenerateHandlingService} from '@ame/editor';
2323
import {SearchesStateService} from '@ame/utils';
2424
import {NamespacesManagerService} from '@ame/namespace-manager';
2525
import {Aspect} from '@ame/meta-model';
26+
import 'cypress-file-upload';
2627

2728
const {mxEventObject, mxEvent} = mxgraphFactory({});
2829

@@ -528,13 +529,25 @@ Cypress.Commands.add('saveAspectModelToWorkspace', () => {
528529
Cypress.Commands.add('openGenerationOpenApiSpec', () => {
529530
cy.intercept(
530531
'POST',
531-
'http://localhost:9091/ame/api/generate/open-api-spec?language=en&output=json&baseUrl=https://example.com&includeQueryApi=false&pagingOption=NO_PAGING',
532+
'http://localhost:9091/ame/api/generate/open-api-spec?language=en&output=json&baseUrl=https://example.com&includeQueryApi=false&pagingOption=NO_PAGING&resourcePath=null&ymlProperties=&jsonProperties=',
532533
{fixture: 'valid-open-api.json'},
533534
);
534535

535536
cy.intercept(
536537
'POST',
537-
'http://localhost:9091/ame/api/generate/open-api-spec?language=en&output=yaml&baseUrl=https://example.com&includeQueryApi=false&pagingOption=NO_PAGING',
538+
'http://localhost:9091/ame/api/generate/open-api-spec?language=en&output=yaml&baseUrl=https://example.com&includeQueryApi=false&pagingOption=NO_PAGING&resourcePath=null&ymlProperties=&jsonProperties=',
539+
{fixture: 'valid-open-api.yaml'},
540+
);
541+
542+
cy.intercept(
543+
'POST',
544+
'http://localhost:9091/ame/api/generate/open-api-spec?language=en&output=json&baseUrl=https://example.com&includeQueryApi=false&pagingOption=NO_PAGING&resourcePath=/resource/%7BresourceId%7D&ymlProperties=&jsonProperties=%7B%0A%20%20%22key%22:%20%22value%22%0A%7D',
545+
{fixture: 'valid-open-api.json'},
546+
);
547+
548+
cy.intercept(
549+
'POST',
550+
'http://localhost:9091/ame/api/generate/open-api-spec?language=en&output=yaml&baseUrl=https://example.com&includeQueryApi=false&pagingOption=NO_PAGING&resourcePath=/resource/%7BresourceId%7D&ymlProperties=resourceId:%0A%20%20name:%20resourceId%0A%20%20in:%20path%0A%20%20description:%20An%20example%20resource%20Id.%0A%20%20required:%20true%0A%20%20schema:%0A%20%20%20%20type:%20string%0A&jsonProperties=',
538551
{fixture: 'valid-open-api.yaml'},
539552
);
540553

0 commit comments

Comments
 (0)