@grafana/openapi-to-k6 0.2.6 → 0.3.0

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 (116) hide show
  1. package/README.md +5 -1
  2. package/dist/constants.js +7 -3
  3. package/dist/generator/k6Client.js +5 -55
  4. package/dist/generator/k6ScriptBuilder.js +256 -0
  5. package/examples/basic_schema/single/k6-script.sample.ts +3 -2
  6. package/examples/basic_schema/single/simpleAPI.ts +1 -1
  7. package/examples/basic_schema/split/k6-script.sample.ts +3 -2
  8. package/examples/basic_schema/split/simpleAPI.schemas.ts +1 -1
  9. package/examples/basic_schema/split/simpleAPI.ts +1 -1
  10. package/examples/basic_schema/tags/default.ts +1 -1
  11. package/examples/basic_schema/tags/k6-script.sample.ts +4 -3
  12. package/examples/basic_schema/tags/simpleAPI.schemas.ts +1 -1
  13. package/examples/form_data_schema/schema.json +6 -3
  14. package/examples/form_data_schema/single/formDataAPI.ts +1 -1
  15. package/examples/form_data_schema/single/k6-script.sample.ts +10 -2
  16. package/examples/form_data_schema/split/formDataAPI.schemas.ts +1 -1
  17. package/examples/form_data_schema/split/formDataAPI.ts +1 -1
  18. package/examples/form_data_schema/split/k6-script.sample.ts +10 -2
  19. package/examples/form_data_schema/tags/default.ts +1 -1
  20. package/examples/form_data_schema/tags/formDataAPI.schemas.ts +1 -1
  21. package/examples/form_data_schema/tags/k6-script.sample.ts +11 -3
  22. package/examples/form_url_encoded_data_schema/schema.json +6 -3
  23. package/examples/form_url_encoded_data_schema/single/formURLEncodedAPI.ts +1 -1
  24. package/examples/form_url_encoded_data_schema/single/k6-script.sample.ts +11 -2
  25. package/examples/form_url_encoded_data_schema/split/formURLEncodedAPI.schemas.ts +1 -1
  26. package/examples/form_url_encoded_data_schema/split/formURLEncodedAPI.ts +1 -1
  27. package/examples/form_url_encoded_data_schema/split/k6-script.sample.ts +11 -2
  28. package/examples/form_url_encoded_data_schema/tags/default.ts +1 -1
  29. package/examples/form_url_encoded_data_schema/tags/formURLEncodedAPI.schemas.ts +1 -1
  30. package/examples/form_url_encoded_data_schema/tags/k6-script.sample.ts +12 -3
  31. package/examples/form_url_encoded_data_with_query_params_schema/schema.json +8 -4
  32. package/examples/form_url_encoded_data_with_query_params_schema/single/formURLEncodedAPIWithQueryParameters.ts +1 -1
  33. package/examples/form_url_encoded_data_with_query_params_schema/single/k6-script.sample.ts +19 -6
  34. package/examples/form_url_encoded_data_with_query_params_schema/split/formURLEncodedAPIWithQueryParameters.schemas.ts +1 -1
  35. package/examples/form_url_encoded_data_with_query_params_schema/split/formURLEncodedAPIWithQueryParameters.ts +1 -1
  36. package/examples/form_url_encoded_data_with_query_params_schema/split/k6-script.sample.ts +19 -6
  37. package/examples/form_url_encoded_data_with_query_params_schema/tags/default.ts +1 -1
  38. package/examples/form_url_encoded_data_with_query_params_schema/tags/formURLEncodedAPIWithQueryParameters.schemas.ts +1 -1
  39. package/examples/form_url_encoded_data_with_query_params_schema/tags/k6-script.sample.ts +14 -3
  40. package/examples/get_request_with_path_parameters_schema/schema.json +2 -1
  41. package/examples/get_request_with_path_parameters_schema/single/k6-script.sample.ts +6 -2
  42. package/examples/get_request_with_path_parameters_schema/single/simpleAPI.ts +1 -1
  43. package/examples/get_request_with_path_parameters_schema/split/k6-script.sample.ts +6 -2
  44. package/examples/get_request_with_path_parameters_schema/split/simpleAPI.schemas.ts +1 -1
  45. package/examples/get_request_with_path_parameters_schema/split/simpleAPI.ts +1 -1
  46. package/examples/get_request_with_path_parameters_schema/tags/default.ts +1 -1
  47. package/examples/get_request_with_path_parameters_schema/tags/k6-script.sample.ts +7 -3
  48. package/examples/get_request_with_path_parameters_schema/tags/simpleAPI.schemas.ts +1 -1
  49. package/examples/headers_schema/schema.json +2 -1
  50. package/examples/headers_schema/single/headerDemoAPI.ts +1 -1
  51. package/examples/headers_schema/single/k6-script.sample.ts +15 -4
  52. package/examples/headers_schema/split/headerDemoAPI.schemas.ts +1 -1
  53. package/examples/headers_schema/split/headerDemoAPI.ts +1 -1
  54. package/examples/headers_schema/split/k6-script.sample.ts +15 -4
  55. package/examples/headers_schema/tags/default.ts +1 -1
  56. package/examples/headers_schema/tags/headerDemoAPI.schemas.ts +1 -1
  57. package/examples/headers_schema/tags/k6-script.sample.ts +16 -5
  58. package/examples/no_title_schema/single/k6-script.sample.ts +3 -2
  59. package/examples/no_title_schema/single/k6Client.ts +1 -1
  60. package/examples/no_title_schema/split/k6-script.sample.ts +3 -2
  61. package/examples/no_title_schema/split/k6Client.schemas.ts +1 -1
  62. package/examples/no_title_schema/split/k6Client.ts +1 -1
  63. package/examples/no_title_schema/tags/default.ts +1 -1
  64. package/examples/no_title_schema/tags/k6-script.sample.ts +4 -3
  65. package/examples/no_title_schema/tags/k6Client.schemas.ts +1 -1
  66. package/examples/post_request_with_query_params/schema.json +14 -7
  67. package/examples/post_request_with_query_params/single/exampleAPI.ts +1 -1
  68. package/examples/post_request_with_query_params/single/k6-script.sample.ts +11 -2
  69. package/examples/post_request_with_query_params/split/exampleAPI.schemas.ts +1 -1
  70. package/examples/post_request_with_query_params/split/exampleAPI.ts +1 -1
  71. package/examples/post_request_with_query_params/split/k6-script.sample.ts +11 -2
  72. package/examples/post_request_with_query_params/tags/default.ts +1 -1
  73. package/examples/post_request_with_query_params/tags/exampleAPI.schemas.ts +1 -1
  74. package/examples/post_request_with_query_params/tags/k6-script.sample.ts +12 -3
  75. package/examples/query_params_schema/schema.json +20 -10
  76. package/examples/query_params_schema/single/exampleAPI.ts +1 -1
  77. package/examples/query_params_schema/single/k6-script.sample.ts +8 -2
  78. package/examples/query_params_schema/split/exampleAPI.schemas.ts +1 -1
  79. package/examples/query_params_schema/split/exampleAPI.ts +1 -1
  80. package/examples/query_params_schema/split/k6-script.sample.ts +8 -2
  81. package/examples/query_params_schema/tags/default.ts +1 -1
  82. package/examples/query_params_schema/tags/exampleAPI.schemas.ts +1 -1
  83. package/examples/query_params_schema/tags/k6-script.sample.ts +9 -3
  84. package/examples/simple_post_request_schema/schema.json +30 -15
  85. package/examples/simple_post_request_schema/single/exampleAPI.ts +1 -1
  86. package/examples/simple_post_request_schema/single/k6-script.sample.ts +16 -2
  87. package/examples/simple_post_request_schema/split/exampleAPI.schemas.ts +1 -1
  88. package/examples/simple_post_request_schema/split/exampleAPI.ts +1 -1
  89. package/examples/simple_post_request_schema/split/k6-script.sample.ts +16 -2
  90. package/examples/simple_post_request_schema/tags/default.ts +1 -1
  91. package/examples/simple_post_request_schema/tags/exampleAPI.schemas.ts +1 -1
  92. package/examples/simple_post_request_schema/tags/k6-script.sample.ts +17 -3
  93. package/package.json +3 -1
  94. package/src/constants.ts +7 -3
  95. package/src/generator/k6Client.ts +3 -72
  96. package/src/generator/k6ScriptBuilder.ts +328 -0
  97. package/tests/e2e/schema.json +135 -18
  98. package/tests/functional-tests/helper.ts +16 -0
  99. package/tests/functional-tests/test-generator/generator.test.ts +154 -0
  100. package/tests/functional-tests/test-sample-k6-scripts/fixtures/schema_using_ref_models.json +394 -0
  101. package/tests/functional-tests/test-sample-k6-scripts/fixtures/schema_with_examples.json +416 -0
  102. package/tests/functional-tests/test-sample-k6-scripts/fixtures/schema_with_no_variables.json +32 -0
  103. package/tests/functional-tests/test-sample-k6-scripts/sampleK6Scripts.test.ts +248 -0
  104. package/tests/functional-tests/test-tags-filtering/tagsFiltering.test.ts +166 -0
  105. package/tests/functional-tests/generator.test.ts +0 -319
  106. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/basic_schema.json +0 -0
  107. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/form_data_schema.json +0 -0
  108. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/form_url_encoded_data_schema.json +0 -0
  109. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/form_url_encoded_data_with_query_params_schema.json +0 -0
  110. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/get_request_with_path_parameters_schema.json +0 -0
  111. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/headers_schema.json +0 -0
  112. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/no_title_schema.json +0 -0
  113. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/post_request_with_query_params.json +0 -0
  114. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/query_params_schema.json +0 -0
  115. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/simple_post_request_schema.json +0 -0
  116. /package/tests/functional-tests/{fixtures → test-tags-filtering/fixtures}/tags_filtering.json +0 -0
@@ -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
  }
@@ -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
+ }
@@ -0,0 +1,154 @@
1
+ import fs from 'fs'
2
+ import os from 'os'
3
+ import path from 'path'
4
+ import {
5
+ afterAll,
6
+ afterEach,
7
+ beforeAll,
8
+ beforeEach,
9
+ describe,
10
+ expect,
11
+ it,
12
+ } from 'vitest'
13
+ import { Mode } from '../../../src/constants'
14
+ import generator from '../../../src/generator'
15
+
16
+ import {
17
+ loadFixture,
18
+ mkdtemp,
19
+ readFile,
20
+ replaceSpacesAndNewLineToSingleSpace,
21
+ rmdir,
22
+ writeFile,
23
+ } from '../helper'
24
+
25
+ const commonSubstringsForAllSDK = [
26
+ 'Automatically generated by',
27
+ 'Do not edit manually',
28
+ 'Service version',
29
+ 'const mergedRequestParameters = this._mergeRequestParameters( requestParameters || {}, this.commonRequestParameters, );',
30
+ 'try { data = response.json(); } catch { data = response.body; }',
31
+ 'return { response, data, };',
32
+ ]
33
+
34
+ const commonSubstringsForK6SampleScript = [`const baseUrl = "<BASE_URL>";`]
35
+
36
+ describe('generator', () => {
37
+ let tempDir: string, schemaDirectory: string
38
+ const allFixtures = fs.readdirSync(path.join(__dirname, 'fixtures'))
39
+
40
+ beforeAll(async () => {
41
+ tempDir = await mkdtemp(path.join(os.tmpdir(), 'sdk-generator-'))
42
+ })
43
+
44
+ afterAll(async () => {
45
+ await rmdir(tempDir, { recursive: true })
46
+ })
47
+
48
+ for (const fixtureName of allFixtures) {
49
+ describe(`test ${fixtureName} OpenAPI schema`, () => {
50
+ let openApiPath: string, generatedSchemaPath: string
51
+ const fixture = loadFixture(path.join(__dirname, 'fixtures', fixtureName))
52
+
53
+ beforeEach(async () => {
54
+ schemaDirectory = await mkdtemp(
55
+ path.join(tempDir, fixtureName.replace('.', '-'))
56
+ )
57
+ // Write the OpenAPI schema to a file
58
+
59
+ openApiPath = path.join(schemaDirectory, 'openapi-schema.json')
60
+
61
+ await writeFile(openApiPath, JSON.stringify(fixture['openapi_schema']))
62
+
63
+ generatedSchemaPath = path.join(schemaDirectory, 'generated-schema')
64
+ })
65
+
66
+ afterEach(async () => {
67
+ await rmdir(schemaDirectory, { recursive: true })
68
+ })
69
+
70
+ it(`should generate SDK client from the OpenAPI schema`, async () => {
71
+ const expectedGeneratedCode = fixture['expected_sdk']
72
+
73
+ await generator({
74
+ openApiPath,
75
+ outputDir: generatedSchemaPath,
76
+ mode: Mode.SINGLE,
77
+ })
78
+
79
+ const generatedFiles = fs.readdirSync(generatedSchemaPath)
80
+ expect(generatedFiles.length).toBe(1)
81
+ expect(generatedFiles[0]).toBeDefined()
82
+ const fileName = path.basename(generatedFiles[0]!)
83
+ expect(fileName).toBe(expectedGeneratedCode.fileName)
84
+ const generatedFilePath = path.join(
85
+ generatedSchemaPath,
86
+ generatedFiles[0]!
87
+ )
88
+ const generatedContent = await readFile(generatedFilePath, 'utf-8')
89
+
90
+ for (const expectedString of [
91
+ ...expectedGeneratedCode['expectedSubstrings'],
92
+ ...commonSubstringsForAllSDK,
93
+ ]) {
94
+ expect(
95
+ replaceSpacesAndNewLineToSingleSpace(generatedContent)
96
+ ).toContain(expectedString)
97
+ }
98
+ })
99
+
100
+ it('should generate a sample K6 script', async () => {
101
+ await generator({
102
+ openApiPath,
103
+ outputDir: generatedSchemaPath,
104
+ shouldGenerateSampleK6Script: true,
105
+ mode: Mode.SINGLE,
106
+ })
107
+
108
+ const generatedFiles = fs.readdirSync(generatedSchemaPath)
109
+ expect(generatedFiles.length).toBe(2)
110
+ const k6ScriptFile = generatedFiles.find((file) =>
111
+ file.includes('k6-script')
112
+ )
113
+ expect(k6ScriptFile).toBeDefined()
114
+ expect(k6ScriptFile).toBe('k6-script.sample.ts')
115
+
116
+ const generatedFilePath = path.join(generatedSchemaPath, k6ScriptFile!)
117
+ const generatedContent = await readFile(generatedFilePath, 'utf-8')
118
+
119
+ for (const expectedString of [...commonSubstringsForK6SampleScript]) {
120
+ expect(generatedContent).toContain(expectedString)
121
+ }
122
+ })
123
+
124
+ it('should not contain types in main file when using split mode', async () => {
125
+ await generator({
126
+ openApiPath,
127
+ outputDir: generatedSchemaPath,
128
+ shouldGenerateSampleK6Script: true,
129
+ mode: Mode.SPLIT,
130
+ })
131
+ const expectedGeneratedCode = fixture['expected_sdk']
132
+ const generatedFiles = fs.readdirSync(generatedSchemaPath)
133
+
134
+ expect(generatedFiles.length).toBe(3)
135
+
136
+ const clientFile = generatedFiles.find((file) =>
137
+ file.includes(expectedGeneratedCode.fileName)
138
+ )
139
+ const schemaFile = generatedFiles.find((file) =>
140
+ file.includes('.schemas.ts')
141
+ )
142
+
143
+ expect(clientFile).toBeDefined()
144
+ expect(schemaFile).toBeDefined()
145
+
146
+ const generatedFilePath = path.join(generatedSchemaPath, clientFile!)
147
+ const generatedContent = await readFile(generatedFilePath, 'utf-8')
148
+
149
+ expect(generatedContent).not.toContain('export type')
150
+ expect(generatedContent).not.toContain('export interface')
151
+ })
152
+ })
153
+ }
154
+ })