diff --git a/.gitignore b/.gitignore index 5e2cca464..14f3ca7db 100644 --- a/.gitignore +++ b/.gitignore @@ -61,5 +61,6 @@ dist/ # AMF models demo/models/*.json +demo/models/flattened/*.json .idea/ diff --git a/demo/flattened-apis.json b/demo/flattened-apis.json new file mode 100644 index 000000000..bd2cf47b2 --- /dev/null +++ b/demo/flattened-apis.json @@ -0,0 +1,21 @@ +{ + "models/demo-api/demo-api.raml": { "type": "RAML 1.0", "flattened": true}, + "models/google-drive-api/google-drive-api.raml": { "type": "RAML 1.0", "flattened": true}, + "models/multi-server/multi-server.yaml": { "type": "OAS 3.0", "mime": "application/yaml", "flattened": true }, + "models/async-api/async-api.yaml": { "type": "ASYNC 2.0", "flattened": true }, + "models/APIC-553/APIC-553.raml": { "type": "RAML 1.0", "flattened": true}, + "models/APIC-554/APIC-554.raml": { "type": "RAML 1.0", "flattened": true}, + "models/APIC-557/APIC-557.yaml": { "type": "OAS 3.0", "flattened": true }, + "models/anyOf/anyOf.yaml": { "type": "ASYNC 2.0", "flattened": true }, + "models/streetlights/streetlights.yaml": { "type": "ASYNC 2.0", "flattened": true }, + "models/test-api/test-api.raml": { "type": "RAML 1.0", "flattened": true}, + "models/test-api/basicAuth.raml": { "type": "RAML 1.0", "flattened": true}, + "models/test-api/documentation.raml": { "type": "RAML 1.0", "flattened": true}, + "models/test-api/extension.raml": { "type": "RAML 1.0", "flattened": true}, + "models/test-api/library.raml": { "type": "RAML 1.0", "flattened": true}, + "models/test-api/overlay.raml": { "type": "RAML 1.0", "flattened": true}, + "models/test-api/person.raml": { "type": "RAML 1.0", "flattened": true}, + "models/representative-service/representative-service.yaml": { "type": "OAS 3.0", "flattened": true }, + "models/APIC-763/APIC-763.raml": { "type": "RAML 1.0", "flattened": true}, + "models/multipart-api/multipart-api.raml": { "type": "RAML 1.0", "flattened": true} +} diff --git a/demo/model.js b/demo/model.js index 72741b45f..3dfd20b12 100644 --- a/demo/model.js +++ b/demo/model.js @@ -1,6 +1,14 @@ +/* eslint-disable no-console */ +// eslint-disable-next-line no-undef const generator = require('@api-components/api-model-generator'); generator('demo/apis.json', { dest: 'demo/models/' -}) -.then(() => console.log('Models created')) -.catch((cause) => console.error(cause)); +}). +then(() => console.log('Models created')). +catch((cause) => console.error(cause)); + +generator('demo/flattened-apis.json', { + dest: 'demo/models/flattened/' +}). +then(() => console.log('Models created')). +catch((cause) => console.error(cause)); diff --git a/test/amf-loader.js b/test/amf-loader.js index 4c79e3745..96f62e8c8 100644 --- a/test/amf-loader.js +++ b/test/amf-loader.js @@ -9,8 +9,9 @@ export class ApiDescribe { /** * @param {string} label * @param {boolean} compact + * @param {boolean} flattened */ - constructor(label, compact=false) { + constructor(label, compact=false, flattened=false) { /** * @type {string} */ @@ -19,6 +20,10 @@ export class ApiDescribe { * @type {boolean} */ this.compact = compact; + /** + * @type {boolean} + */ + this.flattened = flattened; } } @@ -35,6 +40,7 @@ const helper = new HelperElement(); * @typedef {Object} ApiLoadOptions * @property {boolean=} compact Whether to download a compact version of an API * @property {string=} fileName Name of the API file, without the extension + * @property {boolean=} flattened Whether to generate flattened model or not */ /** @@ -80,10 +86,10 @@ const helper = new HelperElement(); * @return {Promise} Promise resolved to API object. */ AmfLoader.load = async (config = {}) => { - const { compact=false, fileName='demo-api' } = config; + const { compact=false, fileName='demo-api', flattened=false } = config; const suffix = compact ? '-compact' : ''; const file = `${fileName}${suffix}.json`; - const url = `${window.location.protocol }//${ window.location.host }/base/demo/models/${ file}`; + const url = `${window.location.protocol}//${window.location.host}/base/demo/models/${flattened? 'flattened/' : ''}${file}`; const response = await fetch(url); if (!response.ok) { throw new Error(`Unable to download ${url}`); @@ -97,7 +103,7 @@ AmfLoader.load = async (config = {}) => { * @param {ApiModel} model Api model. * @return {WebApiModel} Model for the WebApi */ -AmfLoader.lookupWebApi = function(model) { +AmfLoader.lookupWebApi = (model) => { helper.amf = model; return helper._computeApi(model); }; @@ -108,7 +114,7 @@ AmfLoader.lookupWebApi = function(model) { * @param {string} endpoint Endpoint path * @return {EndpointModel|undefined} Model for the endpoint */ -AmfLoader.lookupEndpoint = function(model, endpoint) { +AmfLoader.lookupEndpoint = (model, endpoint) => { helper.amf = model; const webApi = helper._computeApi(model); return helper._computeEndpointByPath(webApi, endpoint); @@ -121,7 +127,7 @@ AmfLoader.lookupEndpoint = function(model, endpoint) { * @param {string} operation Operation name (the verb, lowercase) * @return {OperationModel|undefined} Model for the endpoint */ -AmfLoader.lookupOperation = function(model, endpoint, operation) { +AmfLoader.lookupOperation = (model, endpoint, operation) => { const endPoint = AmfLoader.lookupEndpoint(model, endpoint); const opKey = helper._getAmfKey(helper.ns.aml.vocabularies.apiContract.supportedOperation); const ops = helper._ensureArray(endPoint[opKey]); @@ -135,7 +141,7 @@ AmfLoader.lookupOperation = function(model, endpoint, operation) { * @param {string} operation Operation name (the verb, lowercase) * @return {PayloadModel[]|undefined} Model for the payload */ -AmfLoader.lookupPayload = function(model, endpoint, operation) { +AmfLoader.lookupPayload = (model, endpoint, operation) => { const op = AmfLoader.lookupOperation(model, endpoint, operation); const expects = helper._computeExpects(op); return helper._ensureArray(helper._computePayload(expects)); @@ -154,7 +160,7 @@ AmfLoader.lookupPayload = function(model, endpoint, operation) { * @param {string} operation Operation name (the verb, lowercase) * @return {Array} First item is the endpoint model and the second is the operation model. */ -AmfLoader.lookupEndpointOperation = function(model, endpoint, operation) { +AmfLoader.lookupEndpointOperation = (model, endpoint, operation) => { const endPoint = AmfLoader.lookupEndpoint(model, endpoint); const opKey = helper._getAmfKey(helper.ns.aml.vocabularies.apiContract.supportedOperation); const ops = helper._ensureArray(endPoint[opKey]); @@ -168,11 +174,9 @@ AmfLoader.lookupEndpointOperation = function(model, endpoint, operation) { * @param {string} name Name of the security scheme * @return {SecurityModel} */ -AmfLoader.lookupSecurity = function(model, name) { +AmfLoader.lookupSecurity = (model, name) => { helper.amf = model; - const webApi = helper._hasType(model, helper.ns.aml.vocabularies.document.Document) ? - helper._computeApi(model) : - model; + const webApi = helper._hasType(model, helper.ns.aml.vocabularies.document.Document)? helper._computeApi(model): model; const declares = helper._computeDeclares(webApi) || []; let result = declares.find((item) => { if (item instanceof Array) { @@ -208,11 +212,9 @@ AmfLoader.lookupSecurity = function(model, name) { * @param {string} name Name of the data type * @return {TypeModel} */ -AmfLoader.lookupType = function(model, name) { +AmfLoader.lookupType = (model, name) => { helper.amf = model; - const webApi = helper._hasType(model, helper.ns.aml.vocabularies.document.Document) ? - helper._computeApi(model) : - model; + const webApi = helper._hasType(model, helper.ns.aml.vocabularies.document.Document)? helper._computeApi(model): model; const declares = helper._computeDeclares(webApi) || []; let result = declares.find((item) => { if (item instanceof Array) { @@ -244,7 +246,7 @@ AmfLoader.lookupType = function(model, name) { * @param {string} name Name of the documentation * @return {DocumentationModel} */ -AmfLoader.lookupDocumentation = function(model, name) { +AmfLoader.lookupDocumentation = (model, name) => { helper.amf = model; const webApi = helper._computeApi(model); const key = helper._getAmfKey(helper.ns.aml.vocabularies.core.documentation); @@ -262,7 +264,7 @@ AmfLoader.lookupDocumentation = function(model, name) { * @param {ApiModel} model Api model. * @return {EncodeModel[]} */ -AmfLoader.lookupEncodes = function(model) { +AmfLoader.lookupEncodes = (model) => { if (model instanceof Array) { model = model[0]; } diff --git a/test/api-console-documentation.test.js b/test/api-console-documentation.test.js index 1ce851c05..2d8e1a157 100644 --- a/test/api-console-documentation.test.js +++ b/test/api-console-documentation.test.js @@ -34,6 +34,8 @@ describe('API Console documentation', () => { const googleApi = 'google-drive-api'; const testApi = 'test-api'; + const streetlights = 'streetlights'; + const representativeService = 'representative-service'; let element; let amf; @@ -111,7 +113,7 @@ describe('API Console documentation', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) + new ApiDescribe('Compact model', true), ].forEach(({ label, compact }) => { describe(label, () => { before(async () => { @@ -194,7 +196,7 @@ describe('API Console documentation', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) + new ApiDescribe('Compact model', true), ].forEach(({ label, compact }) => { describe(label, () => { before(async () => { @@ -808,13 +810,14 @@ describe('API Console documentation', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) - ].forEach(({ label, compact }) => { + new ApiDescribe('Compact model', true), + new ApiDescribe('Flattened model', false, true), + ].forEach(({ label, compact, flattened }) => { describe(label, () => { let docShadowRoot; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'streetlights' }); + amf = await AmfLoader.load({ compact, fileName: streetlights, flattened }); }); describe('Async APIs', () => { @@ -888,7 +891,7 @@ describe('API Console documentation', () => { let docShadowRoot; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'representative-service' }); + amf = await AmfLoader.load({ compact, fileName: representativeService }); }); describe('OAS 3.0', () => { @@ -921,7 +924,8 @@ describe('API Console documentation', () => { assert.exists(requestDocumentation.querySelector('.callbacks')); }); - it('should render responses', () => { + it('should render responses', async () => { + await waitUntil(() => Boolean(docShadowRoot.querySelector('.response-documentation'))); assert.exists(docShadowRoot.querySelector('.response-documentation')); }); diff --git a/test/api-console-navigation.test.js b/test/api-console-navigation.test.js index c4d01b2a8..5436f3fe6 100644 --- a/test/api-console-navigation.test.js +++ b/test/api-console-navigation.test.js @@ -27,14 +27,15 @@ describe('API Console navigation', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) - ].forEach(({ label, compact }) => { + new ApiDescribe('Compact model', true), + new ApiDescribe('Flattened model', false, true), + ].forEach(({ label, compact, flattened }) => { describe(label, () => { let element; let amf; before(async () => { - amf = await AmfLoader.load({ compact, fileName: googleApi }); + amf = await AmfLoader.load({ compact, fileName: googleApi, flattened }); }); beforeEach(async () => { @@ -374,8 +375,9 @@ describe('API Console navigation', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) - ].forEach(({ label, compact }) => { + new ApiDescribe('Compact model', true), + new ApiDescribe('Flattened model', false, true), + ].forEach(({ label, compact, flattened }) => { describe(label, () => { let element; let amf; @@ -383,7 +385,7 @@ describe('API Console navigation', () => { describe('RAML Fragments', () => { describe('SecurityScheme fragment', () => { before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'basicAuth' }); + amf = await AmfLoader.load({ compact, fileName: 'basicAuth', flattened }); }); beforeEach(async () => { @@ -408,7 +410,7 @@ describe('API Console navigation', () => { describe('DocumentationItem fragment', () => { before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'documentation' }); + amf = await AmfLoader.load({ compact, fileName: 'documentation', flattened }); }); beforeEach(async () => { @@ -433,7 +435,7 @@ describe('API Console navigation', () => { describe('Extension fragment', () => { before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'extension' }); + amf = await AmfLoader.load({ compact, fileName: 'extension', flattened }); }); beforeEach(async () => { @@ -458,7 +460,7 @@ describe('API Console navigation', () => { describe('Library fragment', () => { before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'library' }); + amf = await AmfLoader.load({ compact, fileName: 'library', flattened }); }); beforeEach(async () => { @@ -483,7 +485,7 @@ describe('API Console navigation', () => { describe('Overlay fragment', () => { before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'overlay' }); + amf = await AmfLoader.load({ compact, fileName: 'overlay', flattened }); }); beforeEach(async () => { @@ -531,7 +533,7 @@ describe('API Console navigation', () => { describe('DataType fragment', () => { before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'person' }); + amf = await AmfLoader.load({ compact, fileName: 'person', flattened }); }); beforeEach(async () => { @@ -559,15 +561,16 @@ describe('API Console navigation', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) - ].forEach(({ label, compact }) => { + new ApiDescribe('Compact model', true), + new ApiDescribe('Flattened model', false, true), + ].forEach(({ label, compact, flattened }) => { describe(label, () => { let element; let amf; describe('Async APIs', () => { before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'streetlights' }); + amf = await AmfLoader.load({ compact, fileName: 'streetlights', flattened }); }); beforeEach(async () => { diff --git a/test/api-console-request.test.js b/test/api-console-request.test.js index 523ce47d8..f2d04feb0 100644 --- a/test/api-console-request.test.js +++ b/test/api-console-request.test.js @@ -711,15 +711,16 @@ describe('API Console request', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) - ].forEach(({ label, compact }) => { + new ApiDescribe('Compact model', true), + new ApiDescribe('Flattened model', false, true), + ].forEach(({ label, compact, flattened }) => { describe(label, () => { let element; let amf; describe('Async APIs', () => { before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'streetlights' }); + amf = await AmfLoader.load({ compact, fileName: 'streetlights', flattened }); }); beforeEach(async () => { @@ -800,10 +801,11 @@ describe('API Console request', () => { await aTimeout(50); }); - it('should render request panel with optional field to overwrite content type', () => { + it('should render request panel with optional field to overwrite content type', async () => { const requestBody = requestBodySection(element); assert.exists(requestBody); + await waitUntil(() => Boolean(requestBody.shadowRoot.querySelector('multipart-payload-editor'))); const multipartPayload = requestBody.shadowRoot.querySelector('multipart-payload-editor'); assert.exists(multipartPayload); diff --git a/test/api-console.amf.test.js b/test/api-console.amf.test.js index f9a705a1d..05517421a 100644 --- a/test/api-console.amf.test.js +++ b/test/api-console.amf.test.js @@ -35,6 +35,14 @@ export const selectOperation = (element, endpointName, operationName) => { }; describe('ApiConsole', () => { + const asyncApi = 'async-api'; + const multiServer = 'multi-server'; + const apic553 = 'APIC-553'; + const apic554 = 'APIC-554'; + const apic557 = 'APIC-557'; + const anyOf = 'anyOf'; + const streetlights = 'streetlights'; + const apic763 = 'APIC-763'; describe('AMF model computations', () => { [ @@ -122,12 +130,10 @@ describe('ApiConsole', () => { new ApiDescribe('Compact model', true), ].forEach(({ label, compact }) => { describe(label, () => { - const fileName = 'multi-server'; - describe('server selection', () => { let amf; before(async () => { - amf = await AmfLoader.load({ compact, fileName }); + amf = await AmfLoader.load({ compact, fileName: multiServer }); }); it('auto-selects the default server', async () => { @@ -148,7 +154,7 @@ describe('ApiConsole', () => { describe('slot rendering', () => { let amf; before(async () => { - amf = await AmfLoader.load({ compact, fileName }); + amf = await AmfLoader.load({ compact, fileName: multiServer }); }); it('renders the slot when page is documentation', async () => { @@ -184,13 +190,14 @@ describe('ApiConsole', () => { [ new ApiDescribe('Regular model'), new ApiDescribe('Compact model', true), - ].forEach(({ label, compact }) => { + new ApiDescribe('Flattened model', false, true), + ].forEach(({ label, compact, flattened }) => { describe(label, () => { let amf; let element; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'async-api' }); + amf = await AmfLoader.load({ compact, fileName: asyncApi, flattened }); }); beforeEach(async () => { @@ -209,13 +216,14 @@ describe('ApiConsole', () => { [ new ApiDescribe('Regular model'), new ApiDescribe('Compact model', true), - ].forEach(({ label, compact }) => { + new ApiDescribe('Flattened model', false, true), + ].forEach(({ label, compact, flattened }) => { describe(label, () => { let amf; let element; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'APIC-553' }); + amf = await AmfLoader.load({ compact, fileName: apic553, flattened }); }); beforeEach(async () => { @@ -241,13 +249,14 @@ describe('ApiConsole', () => { [ new ApiDescribe('Regular model'), new ApiDescribe('Compact model', true), - ].forEach(({ label, compact }) => { + new ApiDescribe('Flattened model', false, true), + ].forEach(({ label, compact, flattened }) => { describe(label, () => { let amf; let element; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'APIC-554' }); + amf = await AmfLoader.load({ compact, fileName: apic554, flattened }); }); beforeEach(async () => { @@ -274,7 +283,7 @@ describe('ApiConsole', () => { let element; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'APIC-557' }); + amf = await AmfLoader.load({ compact, fileName: apic557 }); }); beforeEach(async () => { @@ -304,14 +313,15 @@ describe('ApiConsole', () => { describe('APIC-559', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) - ].forEach(({ label, compact }) => { + new ApiDescribe('Compact model', true), + new ApiDescribe('Flattened model', false, true), + ].forEach(({ label, compact, flattened }) => { describe(label, () => { let amf; let element; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'async-api' }); + amf = await AmfLoader.load({ compact, fileName: asyncApi, flattened }); }); beforeEach(async () => { @@ -334,14 +344,14 @@ describe('ApiConsole', () => { describe('APIC-571', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) + new ApiDescribe('Compact model', true), ].forEach(({ label, compact }) => { describe(label, () => { let amf; let element; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'async-api' }); + amf = await AmfLoader.load({ compact, fileName: asyncApi }); }); beforeEach(async () => { @@ -365,14 +375,15 @@ describe('ApiConsole', () => { describe('APIC-570', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) - ].forEach(({ label, compact }) => { + new ApiDescribe('Compact model', true), + new ApiDescribe('Flattened model', false, true), + ].forEach(({ label, compact, flattened }) => { describe(label, () => { let amf; let element; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'async-api' }); + amf = await AmfLoader.load({ compact, fileName: asyncApi, flattened }); }); beforeEach(async () => { @@ -393,14 +404,15 @@ describe('ApiConsole', () => { describe('APIC-562', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) - ].forEach(({ label, compact }) => { + new ApiDescribe('Compact model', true), + new ApiDescribe('Flattened model', false, true), + ].forEach(({ label, compact, flattened }) => { describe(label, () => { let amf; let element; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'async-api' }); + amf = await AmfLoader.load({ compact, fileName: asyncApi, flattened }); }); beforeEach(async () => { @@ -428,7 +440,7 @@ describe('ApiConsole', () => { let element; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'anyOf' }); + amf = await AmfLoader.load({ compact, fileName: anyOf }); }); beforeEach(async () => { @@ -454,14 +466,14 @@ describe('ApiConsole', () => { describe('APIC-560', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) + new ApiDescribe('Compact model', true), ].forEach(({ label, compact }) => { describe(label, () => { let amf; let element; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'streetlights' }); + amf = await AmfLoader.load({ compact, fileName: streetlights }); }); beforeEach(async () => { @@ -487,7 +499,7 @@ describe('ApiConsole', () => { describe('APIC-763', () => { [ new ApiDescribe('Regular model'), - new ApiDescribe('Compact model', true) + new ApiDescribe('Compact model', true), ].forEach(({ label, compact }) => { describe(label, () => { let amf; @@ -513,7 +525,7 @@ describe('ApiConsole', () => { }; before(async () => { - amf = await AmfLoader.load({ compact, fileName: 'APIC-763' }); + amf = await AmfLoader.load({ compact, fileName: apic763 }); }); beforeEach(async () => {