Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

openapi-schema.js 6.2 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  1. const walk = require('walk-sync')
  2. const path = require('path')
  3. const { get, isPlainObject } = require('lodash')
  4. const allVersions = require('../../lib/all-versions')
  5. const nonEnterpriseDefaultVersion = require('../../lib/non-enterprise-default-version')
  6. const { operations } = require('../../lib/rest')
  7. const dedent = require('dedent')
  8. const schemasPath = path.join(__dirname, '../../lib/rest/static/decorated')
  9. const nonEnterpriseDefaultVersionSchema = operations[nonEnterpriseDefaultVersion]
  10. describe('OpenAPI schema validation', () => {
  11. test('exports an object', () => {
  12. expect(isPlainObject(operations)).toBe(true)
  13. })
  14. // ensure every version defined in allVersions has a correlating static
  15. // decorated file, while allowing decorated files to exist when a version
  16. // is not yet defined in allVersions (e.g., a GHEC static file can exist
  17. // even though the version is not yet supported in the docs)
  18. test('every OpenAPI version must have a schema file in the docs', () => {
  19. const decoratedFilenames = walk(schemasPath)
  20. .map(filename => path.basename(filename, '.json'))
  21. Object.values(allVersions)
  22. .map(version => version.openApiVersionName)
  23. .forEach(openApiBaseName => {
  24. expect(decoratedFilenames.includes(openApiBaseName)).toBe(true)
  25. })
  26. })
  27. test('every value is an array of operations', () => {
  28. let checks = 0
  29. for (const [, operation] of Object.entries(operations)) {
  30. checks++
  31. expect(Array.isArray(operation)).toBe(true)
  32. }
  33. // there are at least 5 versions available (3 ghes [when a version
  34. // has been deprecated], api.github.com, and github.ae)
  35. expect(checks).toBeGreaterThanOrEqual(5)
  36. })
  37. })
  38. function findOperation (method, path) {
  39. return nonEnterpriseDefaultVersionSchema.find(operation => {
  40. return operation.requestPath === path && operation.verb.toLowerCase() === method.toLowerCase()
  41. })
  42. }
  43. describe('x-codeSamples for curl', () => {
  44. test('GET', () => {
  45. const operation = findOperation('GET', '/repos/{owner}/{repo}')
  46. expect(isPlainObject(operation)).toBe(true)
  47. const { source } = operation['x-codeSamples'].find(sample => sample.lang === 'Shell')
  48. const expected = 'curl \\\n -H "Accept: application/vnd.github.v3+json" \\\n https://api.github.com/repos/octocat/hello-world'
  49. expect(source).toEqual(expected)
  50. })
  51. test('operations with required preview headers', () => {
  52. const operationsWithRequiredPreviewHeaders = nonEnterpriseDefaultVersionSchema.filter(operation => {
  53. const previews = get(operation, 'x-github.previews', [])
  54. return previews.some(preview => preview.required)
  55. })
  56. expect(operationsWithRequiredPreviewHeaders.length).toBeGreaterThan(0)
  57. const operationsWithHeadersInCodeSample = operationsWithRequiredPreviewHeaders.filter(operation => {
  58. const { source: codeSample } = operation['x-codeSamples'].find(sample => sample.lang === 'Shell')
  59. return codeSample.includes('-H "Accept: application/vnd.github') && !codeSample.includes('application/vnd.github.v3+json')
  60. })
  61. expect(operationsWithRequiredPreviewHeaders.length).toEqual(operationsWithHeadersInCodeSample.length)
  62. })
  63. })
  64. describe('x-codeSamples for @octokit/core.js', () => {
  65. test('GET', () => {
  66. const operation = findOperation('GET', '/repos/{owner}/{repo}')
  67. expect(isPlainObject(operation)).toBe(true)
  68. const { source } = operation['x-codeSamples'].find(sample => sample.lang === 'JavaScript')
  69. const expected = dedent`await octokit.request('GET /repos/{owner}/{repo}', {
  70. owner: 'octocat',
  71. repo: 'hello-world'
  72. })`
  73. expect(source).toEqual(expected)
  74. })
  75. test('POST', () => {
  76. const operation = findOperation('POST', '/repos/{owner}/{repo}/git/trees')
  77. expect(isPlainObject(operation)).toBe(true)
  78. const { source } = operation['x-codeSamples'].find(sample => sample.lang === 'JavaScript')
  79. const expected = dedent`await octokit.request('POST /repos/{owner}/{repo}/git/trees', {
  80. owner: 'octocat',
  81. repo: 'hello-world',
  82. tree: [
  83. {
  84. path: 'path',
  85. mode: 'mode',
  86. type: 'type',
  87. sha: 'sha',
  88. content: 'content'
  89. }
  90. ]
  91. })`
  92. expect(source).toEqual(expected)
  93. })
  94. test('PUT', () => {
  95. const operation = findOperation('PUT', '/authorizations/clients/{client_id}/{fingerprint}')
  96. expect(isPlainObject(operation)).toBe(true)
  97. const { source } = operation['x-codeSamples'].find(sample => sample.lang === 'JavaScript')
  98. const expected = dedent`await octokit.request('PUT /authorizations/clients/{client_id}/{fingerprint}', {
  99. client_id: 'client_id',
  100. fingerprint: 'fingerprint',
  101. client_secret: 'client_secret'
  102. })`
  103. expect(source).toEqual(expected)
  104. })
  105. test('operations with required preview headers', () => {
  106. const operationsWithRequiredPreviewHeaders = nonEnterpriseDefaultVersionSchema.filter(operation => {
  107. const previews = get(operation, 'x-github.previews', [])
  108. return previews.some(preview => preview.required)
  109. })
  110. expect(operationsWithRequiredPreviewHeaders.length).toBeGreaterThan(0)
  111. // Find something that looks like the following in each code sample:
  112. /*
  113. mediaType: {
  114. previews: [
  115. 'machine-man'
  116. ]
  117. }
  118. */
  119. const operationsWithHeadersInCodeSample = operationsWithRequiredPreviewHeaders.filter(operation => {
  120. const { source: codeSample } = operation['x-codeSamples'].find(sample => sample.lang === 'JavaScript')
  121. return codeSample.match(/mediaType: \{\s+previews: /g)
  122. })
  123. expect(operationsWithRequiredPreviewHeaders.length).toEqual(operationsWithHeadersInCodeSample.length)
  124. })
  125. // skipped because the definition is current missing the `content-type` parameter
  126. // See GitHub issue #155943
  127. test.skip('operation with content-type parameter', () => {
  128. const operation = findOperation('POST', '/markdown/raw')
  129. expect(isPlainObject(operation)).toBe(true)
  130. const { source } = operation['x-codeSamples'].find(sample => sample.lang === 'JavaScript')
  131. const expected = dedent`await octokit.request('POST /markdown/raw', {
  132. data: 'data',
  133. headers: {
  134. 'content-type': 'text/plain; charset=utf-8'
  135. }
  136. })`
  137. expect(source).toEqual(expected)
  138. })
  139. })
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...