@grafana/openapi-to-k6 0.2.6 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +5 -1
  2. package/dist/constants.js +7 -3
  3. package/dist/generator/index.js +13 -6
  4. package/dist/generator/k6Client.js +8 -56
  5. package/dist/generator/k6ScriptBuilder.js +256 -0
  6. package/dist/helper.js +16 -0
  7. package/examples/basic_schema/schema.json +2 -1
  8. package/examples/basic_schema/single/k6-script.sample.ts +3 -2
  9. package/examples/basic_schema/single/simpleAPI.ts +4 -1
  10. package/examples/basic_schema/split/k6-script.sample.ts +3 -2
  11. package/examples/basic_schema/split/simpleAPI.schemas.ts +2 -1
  12. package/examples/basic_schema/split/simpleAPI.ts +3 -1
  13. package/examples/basic_schema/tags/default.ts +3 -1
  14. package/examples/basic_schema/tags/k6-script.sample.ts +4 -3
  15. package/examples/basic_schema/tags/simpleAPI.schemas.ts +2 -1
  16. package/examples/form_data_schema/schema.json +6 -3
  17. package/examples/form_data_schema/single/formDataAPI.ts +8 -6
  18. package/examples/form_data_schema/single/k6-script.sample.ts +10 -2
  19. package/examples/form_data_schema/split/formDataAPI.schemas.ts +5 -5
  20. package/examples/form_data_schema/split/formDataAPI.ts +4 -2
  21. package/examples/form_data_schema/split/k6-script.sample.ts +10 -2
  22. package/examples/form_data_schema/tags/default.ts +4 -2
  23. package/examples/form_data_schema/tags/formDataAPI.schemas.ts +5 -5
  24. package/examples/form_data_schema/tags/k6-script.sample.ts +11 -3
  25. package/examples/form_url_encoded_data_schema/schema.json +6 -3
  26. package/examples/form_url_encoded_data_schema/single/formURLEncodedAPI.ts +8 -6
  27. package/examples/form_url_encoded_data_schema/single/k6-script.sample.ts +11 -2
  28. package/examples/form_url_encoded_data_schema/split/formURLEncodedAPI.schemas.ts +5 -5
  29. package/examples/form_url_encoded_data_schema/split/formURLEncodedAPI.ts +4 -2
  30. package/examples/form_url_encoded_data_schema/split/k6-script.sample.ts +11 -2
  31. package/examples/form_url_encoded_data_schema/tags/default.ts +4 -2
  32. package/examples/form_url_encoded_data_schema/tags/formURLEncodedAPI.schemas.ts +5 -5
  33. package/examples/form_url_encoded_data_schema/tags/k6-script.sample.ts +12 -3
  34. package/examples/form_url_encoded_data_with_query_params_schema/schema.json +8 -4
  35. package/examples/form_url_encoded_data_with_query_params_schema/single/formURLEncodedAPIWithQueryParameters.ts +8 -6
  36. package/examples/form_url_encoded_data_with_query_params_schema/single/k6-script.sample.ts +19 -6
  37. package/examples/form_url_encoded_data_with_query_params_schema/split/formURLEncodedAPIWithQueryParameters.schemas.ts +5 -5
  38. package/examples/form_url_encoded_data_with_query_params_schema/split/formURLEncodedAPIWithQueryParameters.ts +4 -2
  39. package/examples/form_url_encoded_data_with_query_params_schema/split/k6-script.sample.ts +19 -6
  40. package/examples/form_url_encoded_data_with_query_params_schema/tags/default.ts +4 -2
  41. package/examples/form_url_encoded_data_with_query_params_schema/tags/formURLEncodedAPIWithQueryParameters.schemas.ts +5 -5
  42. package/examples/form_url_encoded_data_with_query_params_schema/tags/k6-script.sample.ts +14 -3
  43. package/examples/get_request_with_path_parameters_schema/schema.json +2 -1
  44. package/examples/get_request_with_path_parameters_schema/single/k6-script.sample.ts +6 -2
  45. package/examples/get_request_with_path_parameters_schema/single/simpleAPI.ts +4 -2
  46. package/examples/get_request_with_path_parameters_schema/split/k6-script.sample.ts +6 -2
  47. package/examples/get_request_with_path_parameters_schema/split/simpleAPI.schemas.ts +2 -2
  48. package/examples/get_request_with_path_parameters_schema/split/simpleAPI.ts +3 -1
  49. package/examples/get_request_with_path_parameters_schema/tags/default.ts +3 -1
  50. package/examples/get_request_with_path_parameters_schema/tags/k6-script.sample.ts +7 -3
  51. package/examples/get_request_with_path_parameters_schema/tags/simpleAPI.schemas.ts +2 -2
  52. package/examples/headers_schema/schema.json +2 -1
  53. package/examples/headers_schema/single/headerDemoAPI.ts +5 -3
  54. package/examples/headers_schema/single/k6-script.sample.ts +15 -4
  55. package/examples/headers_schema/split/headerDemoAPI.schemas.ts +1 -1
  56. package/examples/headers_schema/split/headerDemoAPI.ts +5 -3
  57. package/examples/headers_schema/split/k6-script.sample.ts +15 -4
  58. package/examples/headers_schema/tags/default.ts +5 -3
  59. package/examples/headers_schema/tags/headerDemoAPI.schemas.ts +1 -1
  60. package/examples/headers_schema/tags/k6-script.sample.ts +16 -5
  61. package/examples/no_title_schema/single/k6-script.sample.ts +3 -2
  62. package/examples/no_title_schema/single/k6Client.ts +3 -1
  63. package/examples/no_title_schema/split/k6-script.sample.ts +3 -2
  64. package/examples/no_title_schema/split/k6Client.schemas.ts +1 -1
  65. package/examples/no_title_schema/split/k6Client.ts +3 -1
  66. package/examples/no_title_schema/tags/default.ts +3 -1
  67. package/examples/no_title_schema/tags/k6-script.sample.ts +4 -3
  68. package/examples/no_title_schema/tags/k6Client.schemas.ts +1 -1
  69. package/examples/post_request_with_query_params/schema.json +14 -7
  70. package/examples/post_request_with_query_params/single/exampleAPI.ts +8 -6
  71. package/examples/post_request_with_query_params/single/k6-script.sample.ts +11 -2
  72. package/examples/post_request_with_query_params/split/exampleAPI.schemas.ts +5 -5
  73. package/examples/post_request_with_query_params/split/exampleAPI.ts +4 -2
  74. package/examples/post_request_with_query_params/split/k6-script.sample.ts +11 -2
  75. package/examples/post_request_with_query_params/tags/default.ts +4 -2
  76. package/examples/post_request_with_query_params/tags/exampleAPI.schemas.ts +5 -5
  77. package/examples/post_request_with_query_params/tags/k6-script.sample.ts +12 -3
  78. package/examples/query_params_schema/schema.json +20 -10
  79. package/examples/query_params_schema/single/exampleAPI.ts +5 -3
  80. package/examples/query_params_schema/single/k6-script.sample.ts +8 -2
  81. package/examples/query_params_schema/split/exampleAPI.schemas.ts +3 -3
  82. package/examples/query_params_schema/split/exampleAPI.ts +3 -1
  83. package/examples/query_params_schema/split/k6-script.sample.ts +8 -2
  84. package/examples/query_params_schema/tags/default.ts +3 -1
  85. package/examples/query_params_schema/tags/exampleAPI.schemas.ts +3 -3
  86. package/examples/query_params_schema/tags/k6-script.sample.ts +9 -3
  87. package/examples/simple_post_request_schema/schema.json +30 -15
  88. package/examples/simple_post_request_schema/single/exampleAPI.ts +14 -12
  89. package/examples/simple_post_request_schema/single/k6-script.sample.ts +16 -2
  90. package/examples/simple_post_request_schema/split/exampleAPI.schemas.ts +11 -11
  91. package/examples/simple_post_request_schema/split/exampleAPI.ts +4 -2
  92. package/examples/simple_post_request_schema/split/k6-script.sample.ts +16 -2
  93. package/examples/simple_post_request_schema/tags/default.ts +4 -2
  94. package/examples/simple_post_request_schema/tags/exampleAPI.schemas.ts +11 -11
  95. package/examples/simple_post_request_schema/tags/k6-script.sample.ts +17 -3
  96. package/package.json +5 -2
  97. package/src/constants.ts +7 -3
  98. package/src/generator/index.ts +20 -7
  99. package/src/generator/k6Client.ts +6 -73
  100. package/src/generator/k6ScriptBuilder.ts +328 -0
  101. package/src/helper.ts +17 -0
  102. package/tests/e2e/schema.json +135 -18
  103. package/tests/e2e/single/k6Script.ts +54 -1
  104. package/tests/functional-tests/helper.ts +16 -0
  105. package/tests/functional-tests/test-generator/fixtures/basic_parameter_in_ref.json +59 -0
  106. package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/form_data_schema.json +1 -1
  107. package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/form_url_encoded_data_schema.json +1 -1
  108. package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/headers_schema.json +2 -2
  109. package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/simple_post_request_schema.json +1 -1
  110. package/tests/functional-tests/test-generator/generator.test.ts +154 -0
  111. package/tests/functional-tests/test-sample-k6-scripts/fixtures/schema_using_ref_models.json +394 -0
  112. package/tests/functional-tests/test-sample-k6-scripts/fixtures/schema_with_examples.json +416 -0
  113. package/tests/functional-tests/test-sample-k6-scripts/fixtures/schema_with_no_variables.json +32 -0
  114. package/tests/functional-tests/test-sample-k6-scripts/sampleK6Scripts.test.ts +248 -0
  115. package/tests/functional-tests/test-tags-filtering/tagsFiltering.test.ts +166 -0
  116. package/{vite.config.js → vite.config.mjs} +4 -0
  117. package/tests/functional-tests/generator.test.ts +0 -319
  118. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/basic_schema.json +0 -0
  119. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/form_url_encoded_data_with_query_params_schema.json +0 -0
  120. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/get_request_with_path_parameters_schema.json +0 -0
  121. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/no_title_schema.json +0 -0
  122. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/post_request_with_query_params.json +0 -0
  123. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/query_params_schema.json +0 -0
  124. /package/tests/functional-tests/{fixtures → test-tags-filtering/fixtures}/tags_filtering.json +0 -0
@@ -0,0 +1,328 @@
1
+ import { faker } from '@faker-js/faker'
2
+ import {
3
+ camel,
4
+ ClientExtraFilesBuilder,
5
+ ClientFileBuilder,
6
+ ContextSpecs,
7
+ GeneratorVerbOptions,
8
+ GetterPropType,
9
+ kebab,
10
+ NormalizedOutputOptions,
11
+ pascal,
12
+ resolveRef,
13
+ toObjectString,
14
+ } from '@orval/core'
15
+ import Handlebars from 'handlebars'
16
+ import {
17
+ OperationObject,
18
+ ParameterObject,
19
+ ReferenceObject,
20
+ RequestBodyObject,
21
+ SchemaObject,
22
+ } from 'openapi3-ts/oas30'
23
+ import path from 'path'
24
+ import {
25
+ DEFAULT_SCHEMA_TITLE,
26
+ K6_SCRIPT_TEMPLATE,
27
+ SAMPLE_K6_SCRIPT_FILE_NAME,
28
+ } from '../constants'
29
+ import { getDirectoryForPath, getGeneratedClientPath } from '../helper'
30
+ import { logger } from '../logger'
31
+ import { generateTitle } from './k6Client'
32
+
33
+ function getExampleValueForSchema(
34
+ schema: SchemaObject | ReferenceObject,
35
+ context: ContextSpecs
36
+ ) {
37
+ // Handle $ref
38
+ if ('$ref' in schema) {
39
+ const { schema: resolvedSchema } = resolveRef(schema, context)
40
+ return getExampleValueForSchema(resolvedSchema as SchemaObject, context)
41
+ }
42
+
43
+ if ('example' in schema) {
44
+ return `'${schema.example}'`
45
+ }
46
+ let schemaType = schema.type
47
+ if (Array.isArray(schemaType)) {
48
+ schemaType = schemaType[0]
49
+ }
50
+ if (!schemaType) {
51
+ return undefined
52
+ }
53
+ const enumValues = schema.enum
54
+ switch (schemaType) {
55
+ case 'string':
56
+ return enumValues ? `'${enumValues[0]}'` : `'${faker.word.sample()}'`
57
+ case 'number':
58
+ return enumValues ? enumValues[0] : faker.number.int()
59
+ case 'integer':
60
+ return enumValues ? enumValues[0] : faker.number.int()
61
+ case 'boolean':
62
+ return enumValues ? enumValues[0] : faker.datatype.boolean()
63
+ case 'array':
64
+ return '[]'
65
+ case 'object': {
66
+ let objectString = '{\n'
67
+ for (const property in schema.properties) {
68
+ if (schema.properties[property]) {
69
+ const propertyValue = getExampleValueForSchema(
70
+ schema.properties[property],
71
+ context
72
+ )
73
+ objectString += `${property}: ${propertyValue},\n`
74
+ }
75
+ }
76
+
77
+ objectString += '\n}'
78
+ return objectString
79
+ }
80
+ default:
81
+ return null
82
+ }
83
+ }
84
+
85
+ function getExampleValues(
86
+ requiredProps: GeneratorVerbOptions['props'],
87
+ originalOperation: OperationObject,
88
+ context: ContextSpecs
89
+ ): string {
90
+ let exampleValues = ''
91
+ for (const prop of requiredProps) {
92
+ const propType = prop.type as GetterPropType
93
+
94
+ switch (propType) {
95
+ case GetterPropType.QUERY_PARAM: {
96
+ let exampleValue = '{\n'
97
+ for (const param of originalOperation.parameters || []) {
98
+ let resolvedParam: ParameterObject | ReferenceObject
99
+
100
+ if ('$ref' in param) {
101
+ const { schema: resolvedSchema } = resolveRef<ParameterObject>(
102
+ param,
103
+ context
104
+ )
105
+ resolvedParam = resolvedSchema
106
+ } else {
107
+ resolvedParam = param
108
+ }
109
+
110
+ // Only add required query parameters to the example values
111
+ if (resolvedParam.required && resolvedParam.in === 'query') {
112
+ if ('schema' in resolvedParam && resolvedParam.schema) {
113
+ exampleValue += `'${resolvedParam.name}': ${getExampleValueForSchema(resolvedParam.schema, context)},\n`
114
+ }
115
+ }
116
+ }
117
+ exampleValue += '\n}'
118
+ exampleValues += `params = ${exampleValue};\n`
119
+ break
120
+ }
121
+ case GetterPropType.HEADER: {
122
+ let exampleValue = '{\n'
123
+ for (const param of originalOperation.parameters || []) {
124
+ let resolvedParam: ParameterObject | ReferenceObject
125
+
126
+ if ('$ref' in param) {
127
+ const { schema: resolvedSchema } = resolveRef<ParameterObject>(
128
+ param,
129
+ context
130
+ )
131
+ resolvedParam = resolvedSchema
132
+ } else {
133
+ resolvedParam = param
134
+ }
135
+
136
+ // Only add required query parameters to the example values
137
+ if (resolvedParam.required && resolvedParam.in === 'header') {
138
+ if ('schema' in resolvedParam && resolvedParam.schema) {
139
+ exampleValue += `'${resolvedParam.name}': ${getExampleValueForSchema(resolvedParam.schema, context)},\n`
140
+ }
141
+ }
142
+ }
143
+ exampleValue += '\n}'
144
+ exampleValues += `headers = ${exampleValue};\n`
145
+ break
146
+ break
147
+ }
148
+ case GetterPropType.PARAM: {
149
+ let example, paramSchema: SchemaObject | ReferenceObject | undefined
150
+
151
+ for (const parameter of originalOperation.parameters || []) {
152
+ if ('name' in parameter) {
153
+ paramSchema = parameter.schema as SchemaObject
154
+ break
155
+ } else if ('$ref' in parameter) {
156
+ const { schema: resolvedSchema } = resolveRef<ParameterObject>(
157
+ parameter,
158
+ context
159
+ )
160
+ paramSchema = resolvedSchema.schema
161
+ break
162
+ }
163
+ }
164
+
165
+ if (paramSchema) {
166
+ example = getExampleValueForSchema(paramSchema, context)
167
+ }
168
+ if (example) {
169
+ exampleValues += `${prop.name} = ${example};\n`
170
+ }
171
+ break
172
+ }
173
+ case GetterPropType.BODY: {
174
+ // Generate example value from body schema
175
+ const requestBody = originalOperation.requestBody
176
+ let requestBodyExample
177
+ if (!requestBody) {
178
+ break
179
+ }
180
+ let resolvedSchema
181
+ if ('$ref' in requestBody) {
182
+ const { schema } = resolveRef<RequestBodyObject>(requestBody, context)
183
+ resolvedSchema = schema
184
+ } else if ('content' in requestBody) {
185
+ resolvedSchema = requestBody
186
+ }
187
+
188
+ if (resolvedSchema && 'content' in resolvedSchema) {
189
+ // Get the first available content type
190
+ const contentType = Object.keys(resolvedSchema.content)[0]
191
+ if (contentType) {
192
+ const requestBodySchema =
193
+ resolvedSchema.content[contentType]?.schema
194
+ if (requestBodySchema) {
195
+ requestBodyExample = getExampleValueForSchema(
196
+ requestBodySchema,
197
+ context
198
+ )
199
+ }
200
+ }
201
+ }
202
+ if (requestBodyExample) {
203
+ exampleValues += `${prop.name} = ${requestBodyExample};\n`
204
+ }
205
+ break
206
+ }
207
+ }
208
+ }
209
+ return exampleValues
210
+ }
211
+
212
+ function getClientClassName(identifier: string) {
213
+ return generateTitle(pascal(identifier))
214
+ }
215
+
216
+ function getClientObjectName(identifier: string) {
217
+ return camel(generateTitle(pascal(identifier)))
218
+ }
219
+
220
+ export const k6ScriptBuilder: ClientExtraFilesBuilder = async (
221
+ verbOptions: Record<string, GeneratorVerbOptions>,
222
+ output: NormalizedOutputOptions,
223
+ context: ContextSpecs
224
+ ): Promise<ClientFileBuilder[]> => {
225
+ const schemaTitle =
226
+ context.specs[context.specKey]?.info.title || DEFAULT_SCHEMA_TITLE
227
+ const {
228
+ path: pathOfGeneratedClient,
229
+ filename,
230
+ extension,
231
+ } = await getGeneratedClientPath(output.target!, schemaTitle)
232
+ const directoryPath = getDirectoryForPath(pathOfGeneratedClient)
233
+ const generateScriptPath = path.join(
234
+ directoryPath,
235
+ SAMPLE_K6_SCRIPT_FILE_NAME
236
+ )
237
+
238
+ logger.debug(
239
+ `k6ScriptBuilder ~ Generating sample K6 Script\n${JSON.stringify(
240
+ {
241
+ pathOfGeneratedClient,
242
+ filename,
243
+ extension,
244
+ schemaTitle,
245
+ directoryPath,
246
+ generateScriptPath,
247
+ },
248
+ null,
249
+ 2
250
+ )}`
251
+ )
252
+
253
+ const clientFunctionsList = []
254
+ const uniqueVariables = new Set<string>() // Track unique variable names
255
+ const allUniqueTags = new Set<string>()
256
+
257
+ for (const verbOption of Object.values(verbOptions)) {
258
+ if (verbOption.tags && verbOption.tags.length > 0) {
259
+ verbOption.tags.forEach((tag) => allUniqueTags.add(tag))
260
+ } else {
261
+ allUniqueTags.add('default')
262
+ }
263
+
264
+ let clientObjectName
265
+ if (output.mode === 'tags') {
266
+ clientObjectName = getClientObjectName(verbOption.tags[0] || 'default')
267
+ } else {
268
+ clientObjectName = getClientObjectName(schemaTitle)
269
+ }
270
+
271
+ const { operationName, summary, props, originalOperation } = verbOption
272
+ const requiredProps = props.filter((prop) => prop.required)
273
+ // Create example values object
274
+ const exampleValues = getExampleValues(
275
+ requiredProps,
276
+ originalOperation,
277
+ context
278
+ )
279
+
280
+ for (const prop of requiredProps) {
281
+ uniqueVariables.add(prop.name)
282
+ }
283
+ clientFunctionsList.push({
284
+ operationName,
285
+ summary,
286
+ exampleValues,
287
+ requiredParametersString: toObjectString(requiredProps, 'name'),
288
+ clientObjectName,
289
+ })
290
+ }
291
+
292
+ let importStatements = ''
293
+ let clientInitializationStatement = ''
294
+
295
+ if (output.mode === 'tags') {
296
+ for (const tag of allUniqueTags) {
297
+ const { extension } = await getGeneratedClientPath(
298
+ output.target!,
299
+ schemaTitle
300
+ )
301
+ const clientName = getClientClassName(tag)
302
+ importStatements += `import { ${clientName} } from './${kebab(tag)}${extension}';\n`
303
+ clientInitializationStatement += `const ${getClientObjectName(tag)} = new ${clientName}({ baseUrl });\n`
304
+ }
305
+ } else {
306
+ const clientName = getClientClassName(schemaTitle)
307
+ importStatements = `import { ${clientName} } from './${filename}${extension}';\n`
308
+ clientInitializationStatement = `const ${getClientObjectName(schemaTitle)} = new ${clientName}({ baseUrl });\n`
309
+ }
310
+
311
+ const scriptContentData = {
312
+ clientFunctionsList,
313
+ variableDefinition:
314
+ uniqueVariables.size > 0
315
+ ? `let ${Array.from(uniqueVariables).join(', ')};`
316
+ : '',
317
+ importStatements,
318
+ clientInitializationStatement,
319
+ }
320
+ const template = Handlebars.compile(K6_SCRIPT_TEMPLATE)
321
+
322
+ return [
323
+ {
324
+ path: generateScriptPath,
325
+ content: template(scriptContentData),
326
+ },
327
+ ]
328
+ }
package/src/helper.ts CHANGED
@@ -123,6 +123,23 @@ export class OutputOverrider {
123
123
  process.stdout.write = this.originalStdoutWrite
124
124
  process.stderr.write = this.originalStderrWrite
125
125
  }
126
+
127
+ // Method to temporarily write to stdout and stderr
128
+ public async temporarilyWriteToStdoutAndStderr(
129
+ callback: () => Promise<void>
130
+ ) {
131
+ const currentStdoutWrite = process.stdout.write
132
+ const currentStderrWrite = process.stderr.write
133
+
134
+ process.stdout.write = this.originalStdoutWrite
135
+ process.stderr.write = this.originalStderrWrite
136
+ try {
137
+ await callback()
138
+ } finally {
139
+ process.stdout.write = currentStdoutWrite
140
+ process.stderr.write = currentStderrWrite
141
+ }
142
+ }
126
143
  }
127
144
 
128
145
  /**
@@ -17,7 +17,8 @@
17
17
  "required": true,
18
18
  "description": "ID of the item to retrieve",
19
19
  "schema": {
20
- "type": "string"
20
+ "type": "string",
21
+ "example": "12345"
21
22
  }
22
23
  },
23
24
  {
@@ -27,7 +28,8 @@
27
28
  "description": "Whether to return detailed information",
28
29
  "schema": {
29
30
  "type": "boolean",
30
- "default": false
31
+ "default": false,
32
+ "example": true
31
33
  }
32
34
  }
33
35
  ],
@@ -47,7 +49,8 @@
47
49
  "required": true,
48
50
  "description": "ID of the item to create",
49
51
  "schema": {
50
- "type": "string"
52
+ "type": "string",
53
+ "example": "12345"
51
54
  }
52
55
  }
53
56
  ],
@@ -59,10 +62,12 @@
59
62
  "type": "object",
60
63
  "properties": {
61
64
  "name": {
62
- "type": "string"
65
+ "type": "string",
66
+ "example": "Sample Item"
63
67
  },
64
68
  "description": {
65
- "type": "string"
69
+ "type": "string",
70
+ "example": "This is a sample description for the item."
66
71
  }
67
72
  }
68
73
  }
@@ -85,7 +90,8 @@
85
90
  "required": true,
86
91
  "description": "ID of the item to update",
87
92
  "schema": {
88
- "type": "string"
93
+ "type": "string",
94
+ "example": "12345"
89
95
  }
90
96
  }
91
97
  ],
@@ -97,10 +103,12 @@
97
103
  "type": "object",
98
104
  "properties": {
99
105
  "name": {
100
- "type": "string"
106
+ "type": "string",
107
+ "example": "Updated Item Name"
101
108
  },
102
109
  "description": {
103
- "type": "string"
110
+ "type": "string",
111
+ "example": "Updated description for the item."
104
112
  }
105
113
  }
106
114
  }
@@ -123,7 +131,8 @@
123
131
  "required": true,
124
132
  "description": "ID of the item to partially update",
125
133
  "schema": {
126
- "type": "string"
134
+ "type": "string",
135
+ "example": "12345"
127
136
  }
128
137
  }
129
138
  ],
@@ -135,7 +144,8 @@
135
144
  "type": "object",
136
145
  "properties": {
137
146
  "name": {
138
- "type": "string"
147
+ "type": "string",
148
+ "example": "Partially Updated Item Name"
139
149
  }
140
150
  }
141
151
  }
@@ -158,7 +168,8 @@
158
168
  "required": true,
159
169
  "description": "ID of the item to delete",
160
170
  "schema": {
161
- "type": "string"
171
+ "type": "string",
172
+ "example": "12345"
162
173
  }
163
174
  }
164
175
  ],
@@ -178,7 +189,8 @@
178
189
  "required": true,
179
190
  "description": "ID of the item to check",
180
191
  "schema": {
181
- "type": "string"
192
+ "type": "string",
193
+ "example": "12345"
182
194
  }
183
195
  }
184
196
  ],
@@ -204,10 +216,12 @@
204
216
  "type": "object",
205
217
  "properties": {
206
218
  "name": {
207
- "type": "string"
219
+ "type": "string",
220
+ "example": "Form Encoded Item"
208
221
  },
209
222
  "description": {
210
- "type": "string"
223
+ "type": "string",
224
+ "example": "Description for form-urlencoded item."
211
225
  }
212
226
  },
213
227
  "required": ["name"]
@@ -234,7 +248,8 @@
234
248
  "type": "object",
235
249
  "properties": {
236
250
  "name": {
237
- "type": "string"
251
+ "type": "string",
252
+ "example": "Form Data Item"
238
253
  }
239
254
  },
240
255
  "required": ["file", "name"]
@@ -260,7 +275,8 @@
260
275
  "required": true,
261
276
  "description": "ID of the item to retrieve",
262
277
  "schema": {
263
- "type": "string"
278
+ "type": "string",
279
+ "example": "12345"
264
280
  }
265
281
  }
266
282
  ],
@@ -279,7 +295,8 @@
279
295
  "description": "Client ID for the request",
280
296
  "required": true,
281
297
  "schema": {
282
- "type": "string"
298
+ "type": "string",
299
+ "example": "client-123"
283
300
  }
284
301
  },
285
302
  {
@@ -288,11 +305,111 @@
288
305
  "description": "Unique request identifier",
289
306
  "required": false,
290
307
  "schema": {
291
- "type": "string"
308
+ "type": "string",
309
+ "example": "req-56789"
292
310
  }
293
311
  }
294
312
  ]
295
313
  }
314
+ },
315
+ "/users/{userId}/posts/{postId}": {
316
+ "get": {
317
+ "operationId": "getUserPost",
318
+ "parameters": [
319
+ {
320
+ "name": "userId",
321
+ "in": "path",
322
+ "required": true,
323
+ "schema": {
324
+ "type": "string"
325
+ }
326
+ },
327
+ {
328
+ "name": "postId",
329
+ "in": "path",
330
+ "required": true,
331
+ "schema": {
332
+ "type": "string"
333
+ }
334
+ }
335
+ ],
336
+ "responses": {
337
+ "200": {
338
+ "description": "Success",
339
+ "content": {
340
+ "application/json": {
341
+ "schema": {
342
+ "type": "object",
343
+ "properties": {
344
+ "title": {
345
+ "type": "string"
346
+ },
347
+ "content": {
348
+ "type": "string"
349
+ }
350
+ }
351
+ }
352
+ }
353
+ }
354
+ }
355
+ }
356
+ }
357
+ },
358
+ "/items-new-mandatory-headers": {
359
+ "get": {
360
+ "tags": ["ItemsHeader"],
361
+ "summary": "Retrieve a new item with mandatory headers",
362
+ "parameters": [
363
+ {
364
+ "name": "itemId",
365
+ "in": "query",
366
+ "required": true,
367
+ "description": "ID of the item to retrieve",
368
+ "schema": {
369
+ "type": "string",
370
+ "example": "67890"
371
+ }
372
+ },
373
+ {
374
+ "name": "X-Auth-Token",
375
+ "in": "header",
376
+ "description": "Authentication token",
377
+ "required": true,
378
+ "schema": {
379
+ "type": "string",
380
+ "example": "Bearer abcdef12345"
381
+ }
382
+ },
383
+ {
384
+ "name": "X-Correlation-ID",
385
+ "in": "header",
386
+ "description": "Correlation ID for tracking requests",
387
+ "required": true,
388
+ "schema": {
389
+ "type": "string",
390
+ "example": "correlation-12345"
391
+ }
392
+ },
393
+ {
394
+ "name": "X-Optional-Header",
395
+ "in": "header",
396
+ "description": "Optional header",
397
+ "required": false,
398
+ "schema": {
399
+ "type": "string",
400
+ "example": "optional-header-value"
401
+ }
402
+ }
403
+ ],
404
+ "responses": {
405
+ "200": {
406
+ "description": "New item retrieved successfully"
407
+ },
408
+ "400": {
409
+ "description": "Invalid request"
410
+ }
411
+ }
412
+ }
296
413
  }
297
414
  }
298
415
  }
@@ -3,8 +3,15 @@ import { check } from 'k6'
3
3
  import { ComprehensiveAPIClient } from './sdk.ts'
4
4
  /* eslint-enable import/no-unresolved */
5
5
 
6
+ const commonRequestParameters = {
7
+ headers: {
8
+ 'Only-Common-Header': 'test',
9
+ 'Only-Common-Header-2': 'test-2',
10
+ 'X-Correlation-ID': 'only-common-header-value',
11
+ },
12
+ }
6
13
  const baseUrl = 'http://localhost:3000'
7
- const client = new ComprehensiveAPIClient({ baseUrl })
14
+ const client = new ComprehensiveAPIClient({ baseUrl, commonRequestParameters })
8
15
 
9
16
  export const options = {
10
17
  thresholds: {
@@ -79,4 +86,50 @@ export default function () {
79
86
  id: 'test',
80
87
  })
81
88
  checkResponseStatus(getItemsHeaderResponseData.response, 200)
89
+
90
+ const requestParameters = {
91
+ headers: {
92
+ 'Only-Common-Header-2': 'test-common-header-2-parameter',
93
+ 'X-Correlation-ID': 'test-request-parameter',
94
+ },
95
+ }
96
+ const getItemsNewMandatoryHeadersResponseData =
97
+ client.getItemsNewMandatoryHeaders(
98
+ {
99
+ itemId: 'test',
100
+ },
101
+ {
102
+ 'X-Auth-Token': 'test',
103
+ 'X-Correlation-ID': 'test-function-argument',
104
+ },
105
+ requestParameters
106
+ )
107
+ checkResponseStatus(getItemsNewMandatoryHeadersResponseData.response, 200)
108
+
109
+ const requestHeaders =
110
+ getItemsNewMandatoryHeadersResponseData.response.request.headers
111
+ console.log('requestHeaders')
112
+ console.log(requestHeaders)
113
+
114
+ // Validate that the header present only in common request parameters is present in the request
115
+ check(requestHeaders, {
116
+ 'has only-common-header': (r) => r['Only-Common-Header'][0] === 'test',
117
+ })
118
+
119
+ // Validate that the header present only in the request parameters is present in the request
120
+ check(requestHeaders, {
121
+ 'has X-Auth-Token': (r) => r['X-Auth-Token'][0] === 'test',
122
+ })
123
+
124
+ // Validate that the header present in the requestParameters takes precedence over the value in common request parameters
125
+ check(requestHeaders, {
126
+ 'has correct value of Only-Common-Header-2 from request parameters': (r) =>
127
+ r['Only-Common-Header-2'][0] === 'test-common-header-2-parameter',
128
+ })
129
+
130
+ // Validate that the value of the header present in function arguments takes precedence over the value in common request parameters and request parameters
131
+ check(requestHeaders, {
132
+ 'has correct value X-Correlation-ID from function arguments': (r) =>
133
+ r['X-Correlation-Id'][0] === 'test-function-argument',
134
+ })
82
135
  }
@@ -0,0 +1,16 @@
1
+ import fs from 'fs'
2
+ import { promisify } from 'util'
3
+
4
+ export const writeFile = promisify(fs.writeFile)
5
+ export const readFile = promisify(fs.readFile)
6
+ export const mkdtemp = promisify(fs.mkdtemp)
7
+ export const rmdir = promisify(fs.rmdir)
8
+
9
+ export const loadFixture = (filePath: string) => {
10
+ const data = fs.readFileSync(filePath, 'utf-8')
11
+ return JSON.parse(data)
12
+ }
13
+
14
+ export const replaceSpacesAndNewLineToSingleSpace = (input: string): string => {
15
+ return input.replace(/\s+/g, ' ')
16
+ }