UNPKG

openapi-snippet

Version:

Generates code snippets from Open API (previously Swagger) documents.

1,717 lines (1,534 loc) 45.7 kB
'use strict'; const test = require('tape'); const OpenAPISnippets = require('../index'); const { createHarParameterObjects } = require('../openapi-to-har'); const InstagramOpenAPI = require('./instagram_swagger.json'); const BloggerOpenAPI = require('./blogger_swagger.json'); const GitHubOpenAPI = require('./github_swagger.json'); const WatsonOpenAPI = require('./watson_alchemy_language_swagger.json'); const IBMOpenAPI = require('./ibm_watson_alchemy_data_news_api.json'); const PetStoreOpenAPI = require('./petstore_swagger.json'); const PetStoreOpenAPI3 = require('./petstore_oas.json'); const ParameterSchemaReferenceAPI = require('./parameter_schema_reference'); const ParameterExampleReferenceAPI = require('./parameter_example_swagger.json'); const FormDataExampleReferenceAPI = require('./form_data_example.json'); const FormUrlencodedExampleAPI = require('./form_urlencoded_example.json'); const MultipleRequestContentReferenceAPI = require('./multiple_request_content.json'); const ParameterVariationsAPI = require('./parameter_variations_swagger.json'); test('Getting snippets should not result in error or undefined', function (t) { t.plan(1); const result = OpenAPISnippets.getSnippets(InstagramOpenAPI, ['c_libcurl']); t.notEqual(result, undefined); }); test('An invalid target should result in error', function (t) { t.plan(1); try { const result = OpenAPISnippets.getSnippets(BloggerOpenAPI, ['node_asfd']); console.log(result); t.end(); } catch (err) { t.equal(err.toString(), 'Error: Invalid target: node_asfd'); } }); test('Getting snippets for endpoint should not result in error or undefined', function (t) { t.plan(1); const result = OpenAPISnippets.getEndpointSnippets( InstagramOpenAPI, '/geographies/{geo-id}/media/recent', 'get', ['c_libcurl'] ); t.notEqual(result, undefined); }); test('Getting snippets for IBM Watson Alchemy Language should work', function (t) { t.plan(1); const result = OpenAPISnippets.getEndpointSnippets( IBMOpenAPI, '/data/GetNews', 'get', ['node_request'] ); t.notEqual(result, undefined); }); test('Getting snippets for endpoint should contain body', function (t) { t.plan(2); // checks the 'Pages' schema... const result = OpenAPISnippets.getEndpointSnippets( BloggerOpenAPI, '/blogs/{blogId}/pages', 'post', ['node_request'] ); t.true(/body/.test(result.snippets[0].content)); t.true(/subPage/.test(result.snippets[0].content)); }); test('Getting snippets from OpenAPI 3.0.x should work', function (t) { t.plan(1); // checks the 'Pages' schema... const result = OpenAPISnippets.getEndpointSnippets( PetStoreOpenAPI3, '/pets/{id}', 'get', ['node_request'] ); t.notEqual(result, undefined); }); test('Testing server overrides', function (t) { t.plan(12); const result = OpenAPISnippets.getSnippets(PetStoreOpenAPI3, ['c_libcurl']); t.equal(result[0].url, 'https://method-override.example.com/pets'); t.match(result[0].snippets[0].content, /.*method-override.example.com.*/); t.doesNotMatch(result[0].snippets[0].content, /.*petstore.swagger.io.*/); t.equal(result[1].url, 'http://petstore.swagger.io/api/pets/{id}'); t.match(result[1].snippets[0].content, /.*petstore.swagger.io.*/); t.doesNotMatch(result[1].snippets[0].content, /.*example.com.*/); t.equal(result[2].url, 'https://path-override.example.com/pets'); t.match(result[2].snippets[0].content, /.*path-override.example.com.*/); t.doesNotMatch(result[2].snippets[0].content, /.*petstore.swagger.io.*/); t.equal(result[3].url, 'http://petstore.swagger.io/api/pets/{id}'); t.match(result[3].snippets[0].content, /.*petstore.swagger.io.*/); t.doesNotMatch(result[3].snippets[0].content, /.*example.com.*/); }); test('Testing optionally provided parameter values', function (t) { t.plan(2); // checks the 'Pages' schema... const result = OpenAPISnippets.getEndpointSnippets( InstagramOpenAPI, '/locations/search', 'get', ['node_request'], { distance: 5000, 'not-a-query-param': 'foo', } ); t.true(/5000/.test(result.snippets[0].content)); t.false(/not-a-query-param/.test(result.snippets[0].content)); }); test('Testing the case when default is present but a value is provided, use the provided value', function (t) { t.plan(2); // checks the 'Pages' schema... const result = OpenAPISnippets.getEndpointSnippets( GitHubOpenAPI, '/issues', 'get', ['node_request'], { filter: 'assigned', } ); t.true(/assigned/.test(result.snippets[0].content)); t.false(/all/.test(result.snippets[0].content)); // The default value of `filter` is `all` }); test('Testing the case when default is present but no value is provided, use the default', function (t) { t.plan(2); // checks the 'Pages' schema... const result = OpenAPISnippets.getEndpointSnippets( GitHubOpenAPI, '/issues', 'get', ['node_request'] ); t.false(/assigned/.test(result.snippets[0].content)); t.true(/all/.test(result.snippets[0].content)); // The default value of `filter` is `all` }); test('Referenced query parameters should be resolved', function (t) { const result = OpenAPISnippets.getEndpointSnippets( WatsonOpenAPI, '/html/HTMLExtractDates', 'get', ['node_request'] ); const snippet = result.snippets[0].content; t.true(/apikey/.test(snippet)); t.true(/showSourceText/.test(snippet)); t.end(); }); test('Resolve samples from nested examples', function (t) { const result = OpenAPISnippets.getEndpointSnippets( PetStoreOpenAPI, '/user', 'post', ['node_request'] ); const snippet = result.snippets[0].content; t.true(/username.*John78\'/.test(snippet)); t.true(/email.*john.smith@example.com\'/.test(snippet)); t.true(/phone.*\+1\-202\-555\-0192/.test(snippet)); t.true(/password.*drowssaP123/.test(snippet)); t.end(); }); test('Parameters that are Schema References Are Dereferenced', function (t) { const result = OpenAPISnippets.getEndpointSnippets( ParameterSchemaReferenceAPI, '/pets', 'post', ['node_request'] ); const snippet = result.snippets[0].content; t.true(/pet: 'SOME_OBJECT_VALUE'/.test(snippet)); t.end(); }); test('Testing the case when an example is provided, use the provided example value', function (t) { t.plan(2); const result = OpenAPISnippets.getEndpointSnippets( ParameterExampleReferenceAPI, '/pets', 'get', ['node_request'] ); const snippet = result.snippets[0].content; t.true(/ {tags: 'dog,cat', limit: '10'}/.test(snippet)); t.false(/SOME_INTEGER_VALUE/.test(snippet)); t.end(); }); test('Generate snippet with multipart/form-data', function (t) { const result = OpenAPISnippets.getEndpointSnippets( FormDataExampleReferenceAPI, '/pets', 'patch', ['node_request'] ); const snippet = result.snippets[0].content; t.true(/boundary=---011000010111000001101001/.test(snippet)); t.true( /formData: {'pet\[name\]': 'string', 'pet\[tag\]': 'string'}/.test(snippet) ); t.end(); }); test('Generate snippet with multipart/form-data with array', function (t) { const result = OpenAPISnippets.getEndpointSnippets( FormDataExampleReferenceAPI, '/pets/{id}/updatetags', 'patch', ['node_request'] ); const snippet = result.snippets[0].content; t.true(/boundary=---011000010111000001101001/.test(snippet)); t.true(/formData: {'pet\[tags\]': '\["string"\]'}/.test(snippet)); t.end(); }); test('Generate snippet with multipart/form-data with object', function (t) { const result = OpenAPISnippets.getEndpointSnippets( FormDataExampleReferenceAPI, '/pets/{id}/feedingschedule', 'patch', ['node_request'] ); const snippet = result.snippets[0].content; t.true(/boundary=---011000010111000001101001/.test(snippet)); t.true( /formData: {'pet\[feedingSchedule\]': '{"time":"string","food":"string"}'}/.test( snippet ) ); t.end(); }); test('Generate snippets with multiple content types', function (t) { const result = OpenAPISnippets.getEndpointSnippets( MultipleRequestContentReferenceAPI, '/pets', 'patch', ['node_request'] ); t.equal(result.snippets.length, 2); for (const snippet of result.snippets) { if (snippet.mimeType === 'application/json') { t.true( /headers: {'content-type': 'application\/json'}/.test(snippet.content) ); t.true(/body: {name: 'string', tag: 'string'}/.test(snippet.content)); } else if (snippet.mimeType === 'multipart/form-data') { t.true( /headers: {'content-type': 'multipart\/form-data; boundary=---011000010111000001101001'}/.test( snippet.content ) ); t.true( /formData: {'pet\[name\]': 'string', 'pet\[tag\]': 'string', 'pet\[picture\]': 'string'}/.test( snippet.content ) ); } } t.end(); }); test('Query Params Defined for all methods should be resolved', function (t) { const result = OpenAPISnippets.getEndpointSnippets( ParameterExampleReferenceAPI, '/animals', 'get', ['node_request'] ); const snippet = result.snippets[0].content; t.true(/ {tags: 'dog,cat', limit: '10'}/.test(snippet)); t.false(/SOME_INTEGER_VALUE/.test(snippet)); t.end(); }); test('Query Params Defined for all methods are overriden by method definitions', function (t) { const result = OpenAPISnippets.getEndpointSnippets( ParameterExampleReferenceAPI, '/species', 'get', ['node_request'] ); const snippet = result.snippets[0].content; t.true(/ qs: {id: '1,2'}/.test(snippet)); t.end(); }); test('Snippet for Get with no parameters should work', function (t) { const result = OpenAPISnippets.getEndpointSnippets( InstagramOpenAPI, '/media/popular', 'get', ['node_request'] ); const snippet = result.snippets[0].content; t.false(/qs/.test(snippet)); t.end(); }); test('Testing the application/x-www-form-urlencoded example case', function (t) { t.plan(2); const result = OpenAPISnippets.getEndpointSnippets( FormUrlencodedExampleAPI, '/auth/token', 'post', ['shell_curl'] ); const snippet = result.snippets[0].content; t.match(snippet, /.*--data 'id=id\+example\+value'.*/); t.match(snippet, /.*--data 'secret=secret\+example\+value'.*/); t.end(); }); // Tests of createHarParameterObject // First a set of path parameter tests from here: https://swagger.io/docs/specification/serialization/#path test('Path: test that style and explode default correctly (to "simple" and "false") when neither is specified for path', function (t) { const parameter = { name: 'id', in: 'path', }; const expected = [{ name: 'id', value: '1,2,3' }]; const actual = createHarParameterObjects(parameter, [1, 2, 3]); t.deepEqual(actual, expected); t.end(); }); // Simple style tests: test('Path: /users/{id*} with id=5', function (t) { const parameter = { name: 'id', in: 'path', style: 'simple', explode: true, }; const expected = [{ name: 'id', value: '5' }]; const actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{id*} with id=[3,4,5]', function (t) { const parameter = { name: 'id', in: 'path', style: 'simple', explode: true, }; const expected = [{ name: 'id', value: '3,4,5' }]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{id*} with id= {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { const parameter = { name: 'id', in: 'path', style: 'simple', explode: true, }; const expected = [{ name: 'id', value: 'role=admin,firstName=Alex,age=34' }]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{id} with id=5', function (t) { const parameter = { name: 'id', in: 'path', style: 'simple', explode: false, }; const expected = [{ name: 'id', value: '5' }]; const actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{id} with id=[3,4,5]', function (t) { const parameter = { name: 'id', in: 'path', style: 'simple', explode: false, }; const expected = [{ name: 'id', value: '3,4,5' }]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{id} with id= {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { const parameter = { name: 'id', in: 'path', style: 'simple', explode: false, }; const expected = [{ name: 'id', value: 'role,admin,firstName,Alex,age,34' }]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); // Label style tests test('Path: /users/{.id*} with id=5', function (t) { const parameter = { name: 'id', in: 'path', style: 'label', explode: true, }; const expected = [{ name: 'id', value: '.5' }]; const actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{.id*} with id=[3,4,5]', function (t) { const parameter = { name: 'id', in: 'path', style: 'label', explode: true, }; const expected = [{ name: 'id', value: '.3.4.5' }]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{.id*} with id= {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { const parameter = { name: 'id', in: 'path', style: 'label', explode: true, }; const expected = [{ name: 'id', value: '.role=admin.firstName=Alex.age=34' }]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{.id} with id=5', function (t) { const parameter = { name: 'id', in: 'path', style: 'label', explode: false, }; const expected = [{ name: 'id', value: '.5' }]; const actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{.id} with id=[3,4,5]', function (t) { const parameter = { name: 'id', in: 'path', style: 'label', explode: false, }; const expected = [{ name: 'id', value: '.3,4,5' }]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{.id} with id= {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { const parameter = { name: 'id', in: 'path', style: 'label', explode: false, }; const expected = [{ name: 'id', value: '.role,admin,firstName,Alex,age,34' }]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); // Matrix style tests test('Path: /users/{;id*} with id=5', function (t) { const parameter = { name: 'id', in: 'path', style: 'matrix', explode: true, }; const expected = [{ name: 'id', value: ';id=5' }]; const actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{;id*} with id=[3,4,5]', function (t) { const parameter = { name: 'id', in: 'path', style: 'matrix', explode: true, }; const expected = [{ name: 'id', value: ';id=3;id=4;id=5' }]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{;id*} with id= {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { const parameter = { name: 'id', in: 'path', style: 'matrix', explode: true, }; const expected = [{ name: 'id', value: ';role=admin;firstName=Alex;age=34' }]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{;id} with id=5', function (t) { const parameter = { name: 'id', in: 'path', style: 'matrix', explode: false, }; const expected = [{ name: 'id', value: ';id=5' }]; const actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{;id} with id=[3,4,5]', function (t) { const parameter = { name: 'id', in: 'path', style: 'matrix', explode: false, }; const expected = [{ name: 'id', value: ';id=3,4,5' }]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Path: /users/{;id} with id= {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { const parameter = { name: 'id', in: 'path', style: 'matrix', explode: false, }; const expected = [ { name: 'id', value: ';id=role,admin,firstName,Alex,age,34' }, ]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); //// Query Parameters: Test cases from https://swagger.io/docs/specification/serialization/#query // Form Tests test('Query: /users{?id*} with id= 5', function (t) { const parameter = { name: 'id', in: 'query', style: 'form', explode: true, }; const expected = [{ name: 'id', value: '5' }]; const actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); t.end(); }); test('Query: /users{?id*} with id=[3,4,5]', function (t) { const parameter = { name: 'id', in: 'query', style: 'form', explode: true, }; const expected = [ { name: 'id', value: '3' }, { name: 'id', value: '4' }, { name: 'id', value: '5' }, ]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Query: /users{?id*} with id={"role": "admin", "firstName": "Alex", "age": 34}', function (t) { const parameter = { name: 'id', in: 'query', style: 'form', explode: true, }; const expected = [ { name: 'role', value: 'admin' }, { name: 'firstName', value: 'Alex' }, { name: 'age', value: '34' }, ]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); test('Query: /users{?id} with id= 5', function (t) { const parameter = { name: 'id', in: 'query', style: 'form', explode: false, }; const expected = [{ name: 'id', value: '5' }]; const actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); t.end(); }); test('Query: /users{?id} with id=[3,4,5]', function (t) { const parameter = { name: 'id', in: 'query', style: 'form', explode: false, }; const expected = [{ name: 'id', value: '3,4,5' }]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Query: /users{?id} with id={"role": "admin", "firstName": "Alex", "age": 34}', function (t) { const parameter = { name: 'id', in: 'query', style: 'form', explode: false, }; const expected = [{ name: 'id', value: 'role,admin,firstName,Alex,age,34' }]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); test('Query: test that style and explode default correctly (to "form" and "true") when neither is specified for query', function (t) { const parameter = { name: 'id', in: 'query', }; const expected = [ { name: 'firstName', value: 'Alex' }, { name: 'age', value: '34' }, ]; const actual = createHarParameterObjects(parameter, { firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); // Space Delimited Tests // Note: There are less scenarios for this and no special URI Template test('Query: /users{?id*} with id=[3,4,5], spaceDelimited', function (t) { const parameter = { name: 'id', in: 'query', style: 'spaceDelimited', explode: true, }; const expected = [ { name: 'id', value: '3' }, { name: 'id', value: '4' }, { name: 'id', value: '5' }, ]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Query: /users{?id} with id=[3,4,5], spaceDelimited', function (t) { const parameter = { name: 'id', in: 'query', style: 'spaceDelimited', explode: false, }; const expected = [{ name: 'id', value: '3 4 5' }]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); // Pipe Delimited Tests // Note: There are less scenarios for this and no special URI Template test('Query: /users{?id*} with id=[3,4,5], pipeDelimited', function (t) { const parameter = { name: 'id', in: 'query', style: 'pipeDelimited', explode: true, }; const expected = [ { name: 'id', value: '3' }, { name: 'id', value: '4' }, { name: 'id', value: '5' }, ]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Query: /users{?id} with id=[3,4,5], pipeDelimited', function (t) { const parameter = { name: 'id', in: 'query', style: 'pipeDelimited', explode: false, }; const expected = [{ name: 'id', value: '3|4|5' }]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); // DeepObject // Spec doesn't say what to do if explode false. We just assume deepOject ignores explode // as no alternative serialization is defined when explode is false. test('Query: deepObject with id={"role": "admin", "firstName": "Alex", "age": 34}', function (t) { const parameter = { name: 'id', in: 'query', style: 'deepObject', }; const expected = [ { name: 'id[role]', value: 'admin', }, { name: 'id[firstName]', value: 'Alex', }, { name: 'id[age]', value: '34', }, ]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); //// Header Parameters https://swagger.io/docs/specification/serialization/#header test('Header: {id} with X-MyHeader = 5', function (t) { const parameter = { name: 'X-MyHeader', in: 'header', style: 'simple', explode: false, }; const expected = [{ name: 'X-MyHeader', value: '5' }]; const actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); t.end(); }); test('Header: {id} with X-MyHeader = [3,4,5]', function (t) { const parameter = { name: 'X-MyHeader', in: 'header', style: 'simple', explode: false, }; const expected = [{ name: 'X-MyHeader', value: '3,4,5' }]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Header: {id} with X-MyHeader = {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { const parameter = { name: 'X-MyHeader', in: 'header', style: 'simple', explode: false, }; const expected = [ { name: 'X-MyHeader', value: 'role,admin,firstName,Alex,age,34' }, ]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); test('Header: {id*} with X-MyHeader = 5', function (t) { const parameter = { name: 'X-MyHeader', in: 'header', style: 'simple', explode: true, }; const expected = [{ name: 'X-MyHeader', value: '5' }]; const actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); t.end(); }); test('Header: {id*} with X-MyHeader = [3,4,5]', function (t) { const parameter = { name: 'X-MyHeader', in: 'header', style: 'simple', explode: true, }; const expected = [{ name: 'X-MyHeader', value: '3,4,5' }]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Header: {id*} with X-MyHeader = {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { const parameter = { name: 'X-MyHeader', in: 'header', style: 'simple', explode: true, }; const expected = [ { name: 'X-MyHeader', value: 'role=admin,firstName=Alex,age=34' }, ]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); test('Header: Test that style and explode default to simple/false when not provided', function (t) { const parameter = { name: 'X-MyHeader', in: 'header', }; const expected = [ { name: 'X-MyHeader', value: 'role,admin,firstName,Alex,age,34' }, ]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); //// Cookie Parameters https://swagger.io/docs/specification/serialization/#cookie test("Cookie: Test that it doesn't throw an error if style and explode are missing", function (t) { const parameter = { name: 'id', in: 'cookie', }; let expected = [{ name: 'id', value: '5' }]; let actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); // At the time of writing the spec doesn't actually show any test cases for exploded arrays or objects // so I assume they are not "legal" t.end(); }); test('Cookie: id = 5', function (t) { const parameter = { name: 'id', in: 'cookie', style: 'form', explode: true, }; const expected = [{ name: 'id', value: '5' }]; const actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); t.end(); }); test('Cookie: id={id} with id = 5', function (t) { const parameter = { name: 'id', in: 'cookie', style: 'form', explode: false, }; const expected = [{ name: 'id', value: '5' }]; const actual = createHarParameterObjects(parameter, 5); t.deepEqual(actual, expected); t.end(); }); test('Cookie: id={id} with id = [3,4,5]', function (t) { const parameter = { name: 'id', in: 'cookie', style: 'form', explode: false, }; const expected = [{ name: 'id', value: '3,4,5' }]; const actual = createHarParameterObjects(parameter, [3, 4, 5]); t.deepEqual(actual, expected); t.end(); }); test('Cookie: id={id} with id = {role: "admin", firstName: "Alex", age: 34}', function (t) { const parameter = { name: 'id', in: 'cookie', style: 'form', explode: false, }; const expected = [{ name: 'id', value: 'role,admin,firstName,Alex,age,34' }]; const actual = createHarParameterObjects(parameter, { role: 'admin', firstName: 'Alex', age: 34, }); t.deepEqual(actual, expected); t.end(); }); //// More Tests with Snippets const setParameterValues = function ( parameter, value, locationOfParameter, locationOfExample, style, explode ) { if (typeof style === 'undefined') { delete parameter.style; } else { parameter.style = style; } if (typeof explode === 'undefined') { delete parameter.explode; } else { parameter.explode = explode; } delete parameter.default; delete parameter.example; delete parameter.examples; parameter.in = locationOfParameter; if (locationOfExample === 'default') { parameter.default = value; } else if (locationOfExample === 'example') { parameter.example = value; } else if (locationOfExample === 'examples') { parameter.examples = { firstExample: { summary: 'This is a summary', value, }, }; } }; /** * The set of options for testing a parameter scenario * @typedef {Object} ParameterOptions * @property {string} api - The API to use for the test * @property {string} path - The path within the API to use for the test * @property {string} method - The method to use on the path * @property {string} in - The location of the parameter: `query`, `path`, `header` * @property {string} parameterName - The name of the parameter to test with * @property {*?} value - The value to assign to either `default`, `example` or the first entry in `examples` * @property {string} locationOfExample - The location of the example value: `default`, `example`, `examples`. * This parameter determines which of these three locations will have the specified `value`. The other * locations will be `undefined`. * @property {string?} style - Optional: The serialization style for the parameter. Only `form` and `simple` are fully supported. * Per the spec: defaults to `form` for `query` and `cookie` params and defaults to `simple` for `path` and `header` params. * @property {boolean?} explode - Optional: Determines if array and object values should be "exploded" into multiple key-value pairs. * Per the spec: defaults to `true` only for `form` parameters. Defaults to `false` for all other styles. * @property {string} expectedString - A string that is expected to be found in the generated `shell_curl` * code snippet for the specified operation/parameter. * @property {Object?} values - Optional: A set of key value pairs to use as parameter values. */ /** * * @param {*} t * @param {ParameterOptions} options - The test scenario */ const runParameterTest = function (t, options) { const { api, path, method, in: locationOfParameter, parameterName, value, locationOfExample, style, explode, expectedString, values, } = options; const apiCopy = JSON.parse(JSON.stringify(api)); const parameters = apiCopy.paths[path][method].parameters; const parameter = parameters.find((p) => p.name === parameterName); setParameterValues( parameter, value, locationOfParameter, locationOfExample, style, explode ); const result = OpenAPISnippets.getEndpointSnippets( apiCopy, path, method, ['shell_curl'], values ); const snippet = result.snippets[0].content; // note: the shell_curl snippets uriEncode commas in query parameters (but not path parameters). // So we'll uriEncode and commas that might be in `expectedString` const encodedCommaExpectationString = locationOfParameter === 'query' ? expectedString.replaceAll(',', '%2C') : expectedString; t.true( snippet.includes(encodedCommaExpectationString), `expected '${encodedCommaExpectationString}' in '${snippet}'` ); }; const allPetsScenario = { api: ParameterVariationsAPI, path: '/pets', method: 'get', parameterName: 'id', }; const singlePetScenario = { api: ParameterVariationsAPI, path: '/pets/{id}', method: 'get', parameterName: 'id', }; test('Query parameter with template {?id} with object value', function (t) { const testOptions = Object.assign({}, allPetsScenario, { in: 'query', parameterName: 'id', value: { role: 'admin', firstName: 'Alex', age: 34, }, explode: false, locationOfExample: 'default', expectedString: 'id=role%2Cadmin%2CfirstName%2CAlex%2Cage%2C34', }); runParameterTest(t, testOptions); t.end(); }); test('Query parameter with template {?id*} with object value', function (t) { const testOptions = Object.assign({}, allPetsScenario, { in: 'query', parameterName: 'id', value: { role: 'admin', firstName: 'Alex', age: 34, }, explode: true, locationOfExample: 'default', expectedString: 'role=admin&firstName=Alex&age=34', }); runParameterTest(t, testOptions); t.end(); }); test('Query parameter with template {?id} with array value', function (t) { const testOptions = Object.assign({}, allPetsScenario, { in: 'query', parameterName: 'id', value: [3, 4, 5], explode: false, locationOfExample: 'default', expectedString: 'id=3%2C4%2C5', }); runParameterTest(t, testOptions); t.end(); }); test('Query parameter with template {?id*} with array value', function (t) { const testOptions = Object.assign({}, allPetsScenario, { in: 'query', parameterName: 'id', value: [3, 4, 5], explode: true, locationOfExample: 'default', expectedString: 'id=3&id=4&id=5', }); runParameterTest(t, testOptions); t.end(); }); test('Query parameter with with spaceDelimited style array value', function (t) { const testOptions = Object.assign({}, allPetsScenario, { in: 'query', parameterName: 'id', value: [3, 4, 5], style: 'spaceDelimited', explode: false, locationOfExample: 'default', expectedString: 'id=3%204%205', }); runParameterTest(t, testOptions); t.end(); }); test('Query parameter with pipeDelimited array value', function (t) { const testOptions = Object.assign({}, allPetsScenario, { in: 'query', parameterName: 'id', value: [3, 4, 5], style: 'pipeDelimited', explode: false, locationOfExample: 'default', expectedString: 'id=3%7C4%7C5', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{id} with object value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: { role: 'admin', firstName: 'Alex', age: 34, }, explode: false, locationOfExample: 'example', expectedString: '/pets/role,admin,firstName,Alex,age,34', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{id*} with object value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: { role: 'admin', firstName: 'Alex', age: 34, }, explode: true, locationOfExample: 'example', expectedString: '/pets/role=admin,firstName=Alex,age=34', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{id} with array value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: [3, 4, 5], explode: false, locationOfExample: 'example', expectedString: 'pets/3,4,5', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{id*} with array value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: [3, 4, 5], explode: true, locationOfExample: 'example', expectedString: 'pets/3,4,5', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{.id} with primitive value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: 5, style: 'label', explode: false, locationOfExample: 'example', expectedString: '/pets/.5', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{.id*} with primitive value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: 5, explode: true, style: 'label', locationOfExample: 'example', expectedString: '/pets/.5', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{.id} with object value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: { role: 'admin', firstName: 'Alex', age: 34, }, style: 'label', explode: false, locationOfExample: 'example', expectedString: '/pets/.role,admin,firstName,Alex,age,34', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{.id*} with object value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: { role: 'admin', firstName: 'Alex', age: 34, }, explode: true, style: 'label', locationOfExample: 'example', expectedString: '/pets/.role=admin.firstName=Alex.age=34', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{.id} with array value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: [3, 4, 5], explode: false, style: 'label', locationOfExample: 'example', expectedString: 'pets/.3,4,5', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{.id*} with array value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: [3, 4, 5], explode: true, style: 'label', locationOfExample: 'example', expectedString: 'pets/.3.4.5', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{;id} with primitive value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: 5, style: 'matrix', explode: false, locationOfExample: 'example', expectedString: '/pets/;id=5', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{;id*} with primitive value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: 5, explode: true, style: 'matrix', locationOfExample: 'example', expectedString: '/pets/;id=5', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{;id} with object value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: { role: 'admin', firstName: 'Alex', age: 34, }, style: 'matrix', explode: false, locationOfExample: 'example', expectedString: '/pets/;id=role,admin,firstName,Alex,age,34', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{;id*} with object value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: { role: 'admin', firstName: 'Alex', age: 34, }, explode: true, style: 'matrix', locationOfExample: 'example', expectedString: '/pets/;role=admin;firstName=Alex;age=34', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{;id} with array value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: [3, 4, 5], explode: false, style: 'matrix', locationOfExample: 'example', expectedString: 'pets/;id=3,4,5', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with template /pets/{;id*} with array value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: [3, 4, 5], explode: true, style: 'matrix', locationOfExample: 'example', expectedString: 'pets/;id=3;id=4;id=5', }); runParameterTest(t, testOptions); t.end(); }); test('Header parameter with template {id} with object value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'header', parameterName: 'id', value: { role: 'admin', firstName: 'Alex', age: 34, }, explode: false, locationOfExample: 'example', expectedString: "--header 'id: role,admin,firstName,Alex,age,34'", }); runParameterTest(t, testOptions); t.end(); }); test('Header parameter with template {id*} with object value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'header', parameterName: 'id', value: { role: 'admin', firstName: 'Alex', age: 34, }, explode: true, locationOfExample: 'example', expectedString: "--header 'id: role=admin,firstName=Alex,age=34'", }); runParameterTest(t, testOptions); t.end(); }); test('Header parameter with template {id} with array value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'header', parameterName: 'id', value: [3, 4, 5], explode: false, locationOfExample: 'example', expectedString: "--header 'id: 3,4,5'", }); runParameterTest(t, testOptions); t.end(); }); test('Header parameter with template {id*} with array value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'header', parameterName: 'id', value: [3, 4, 5], explode: true, locationOfExample: 'example', expectedString: "--header 'id: 3,4,5'", }); runParameterTest(t, testOptions); t.end(); }); test('Query parameter with sample given by examples key', function (t) { const testOptions = Object.assign({}, allPetsScenario, { in: 'query', parameterName: 'id', value: [3, 4, 5], locationOfExample: 'examples', expectedString: 'id=3&id=4&id=5', }); runParameterTest(t, testOptions); t.end(); }); test('Path parameter with sample given by examples key', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'path', parameterName: 'id', value: [3, 4, 5], locationOfExample: 'examples', expectedString: '/pets/3,4,5', }); runParameterTest(t, testOptions); t.end(); }); test('Header parameter with sample given by examples key', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'header', parameterName: 'id', value: [3, 4, 5], locationOfExample: 'examples', expectedString: "--header 'id: 3,4,5'", }); runParameterTest(t, testOptions); t.end(); }); test('Header parameter defined in operation overrides header parameter of same name in path', function (t) { const result = OpenAPISnippets.getEndpointSnippets( ParameterVariationsAPI, '/pets/{id}', 'get', ['shell_curl'] ); const snippet = result.snippets[0].content; t.match(snippet, /--header 'X-MYHEADER: SOME_STRING_VALUE'/); t.end(); }); test('Path parameter defined in operation overrides header parameter of same name in path', function (t) { const result = OpenAPISnippets.getEndpointSnippets( ParameterVariationsAPI, '/pets/{id}', 'get', ['shell_curl'] ); const snippet = result.snippets[0].content; t.match(snippet, /\/pets\/role,admin,firstName,Alex,age,34/); t.end(); }); test('Header parameter defined in operation (not in path) object', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'header', parameterName: 'X-MYHEADER', value: [3, 4, 5], locationOfExample: 'examples', expectedString: "--header 'X-MYHEADER: 3,4,5'", }); runParameterTest(t, testOptions); t.end(); }); test('Cookie parameter with explode = true', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'cookie', parameterName: 'id', value: 5, explode: true, locationOfExample: 'example', expectedString: '--cookie id=5', }); runParameterTest(t, testOptions); t.end(); }); test('Cookie parameter with template id={id} with primitive value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'cookie', parameterName: 'id', value: 5, explode: false, locationOfExample: 'examples', expectedString: '--cookie id=5', }); runParameterTest(t, testOptions); t.end(); }); test('Cookie parameter with template id={id} with object value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'cookie', parameterName: 'id', value: { role: 'admin', firstName: 'Alex', age: 34, }, explode: false, locationOfExample: 'default', expectedString: '--cookie id=role%2Cadmin%2CfirstName%2CAlex%2Cage%2C34', }); runParameterTest(t, testOptions); t.end(); }); test('Cookie parameter with template id={id} with array value', function (t) { const testOptions = Object.assign({}, singlePetScenario, { in: 'cookie', parameterName: 'id', value: [3, 4, 5], explode: false, locationOfExample: 'example', expectedString: '--cookie id=3%2C4%2C5', }); runParameterTest(t, testOptions); t.end(); }); test('A reference in an examples object is resolved', function (t) { const result = OpenAPISnippets.getEndpointSnippets( ParameterVariationsAPI, '/animals', 'get', ['shell_curl'] ); const snippet = result.snippets[0].content; t.match(snippet, /tags=dog%2Ccat/); t.end(); });