Skip to content

Commit 8b9ad4b

Browse files
kanadguptaerunion
andauthored
refactor(open/openapi/validate): return promises, fix tests (#410)
* refactor(validate): use console.info(), return promise - console.info is so we can safely use console.log() statements when debugging more easily - returning the value allows us to write more robust tests * refactor: return expect, rather than async/await with no return idk, this just felt weird... i hate JS * test: check for resolved output, rather than console output * refactor: return Promise and update test - returning the value allows us to write more robust tests * refactor: return promise in openapi.js, use console.info - console.info() makes it so it's easier for us to use console.log while debugging - returning the promise allows us to write more robust tests * test: refactor tests to check for command output * fix: don't allow to create new version from doc commands * revert: don't fix docs stuff in this branch This reverts commit afeaf7b. For the sake of confining the scope of these changes, I'm reverting this and will fix this in a separate PR focused on our docs commands. * Apply suggestions from code review Co-authored-by: Jon Ursenbach <erunion@users.noreply.github.com> Co-authored-by: Jon Ursenbach <erunion@users.noreply.github.com>
1 parent 5b2220c commit 8b9ad4b

File tree

6 files changed

+128
-135
lines changed

6 files changed

+128
-135
lines changed

__tests__/cmds/open.test.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const chalk = require('chalk');
12
const config = require('config');
23
const configStore = require('../../src/lib/configstore');
34
const cmd = require('../../src/cmds/open');
@@ -12,18 +13,15 @@ describe('rdme open', () => {
1213

1314
it('should open the project', () => {
1415
expect.assertions(2);
15-
console.log = jest.fn();
1616
configStore.set('project', 'subdomain');
1717

18+
const projectUrl = 'https://subdomain.readme.io';
19+
1820
function mockOpen(url) {
19-
expect(url).toBe('https://subdomain.readme.io');
21+
expect(url).toBe(projectUrl);
2022
return Promise.resolve();
2123
}
2224

23-
return cmd.run({ mockOpen }).then(() => {
24-
expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/opening (.*)subdomain.readme.io/i));
25-
26-
console.log.mockRestore();
27-
});
25+
return expect(cmd.run({ mockOpen })).resolves.toBe(`Opening ${chalk.green(projectUrl)} in your browser...`);
2826
});
2927
});

__tests__/cmds/openapi.test.js

Lines changed: 94 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const nock = require('nock');
2+
const chalk = require('chalk');
23
const config = require('config');
34
const fs = require('fs');
45
const promptHandler = require('../../src/lib/prompts');
@@ -9,25 +10,41 @@ const APIError = require('../../src/lib/apiError');
910
const key = 'API_KEY';
1011
const id = '5aa0409b7cf527a93bfb44df';
1112
const version = '1.0.0';
13+
const exampleRefLocation = `${config.host}/project/example-project/1.0.1/refs/ex`;
14+
const successfulMessageBase = [
15+
'',
16+
`\t${chalk.green(exampleRefLocation)}`,
17+
'',
18+
'To update your OpenAPI or Swagger definition, run the following:',
19+
'',
20+
`\t${chalk.green(`rdme openapi FILE --key=${key} --id=1`)}`,
21+
];
22+
const successfulUpload = [
23+
"You've successfully uploaded a new OpenAPI file to your ReadMe project!",
24+
...successfulMessageBase,
25+
].join('\n');
26+
27+
const successfulUpdate = [
28+
"You've successfully updated an OpenAPI file on your ReadMe project!",
29+
...successfulMessageBase,
30+
].join('\n');
1231

1332
jest.mock('../../src/lib/prompts');
1433

1534
const getCommandOutput = () => {
16-
return [console.warn.mock.calls.join('\n\n'), console.log.mock.calls.join('\n\n')].filter(Boolean).join('\n\n');
35+
return [console.warn.mock.calls.join('\n\n'), console.info.mock.calls.join('\n\n')].filter(Boolean).join('\n\n');
1736
};
1837

1938
describe('rdme openapi', () => {
20-
const exampleRefLocation = `${config.host}/project/example-project/1.0.1/refs/ex`;
21-
2239
beforeAll(() => nock.disableNetConnect());
2340

2441
beforeEach(() => {
25-
console.log = jest.fn();
42+
console.info = jest.fn();
2643
console.warn = jest.fn();
2744
});
2845

2946
afterEach(() => {
30-
console.log.mockRestore();
47+
console.info.mockRestore();
3148
console.warn.mockRestore();
3249

3350
nock.cleanAll();
@@ -41,7 +58,7 @@ describe('rdme openapi', () => {
4158
['OpenAPI 3.0', 'yaml', '3.0'],
4259
['OpenAPI 3.1', 'json', '3.1'],
4360
['OpenAPI 3.1', 'yaml', '3.1'],
44-
])('should support uploading a %s definition (format: %s)', (_, format, specVersion) => {
61+
])('should support uploading a %s definition (format: %s)', async (_, format, specVersion) => {
4562
const mock = nock(config.host)
4663
.get('/api/v1/api-specification')
4764
.basicAuth({ user: key })
@@ -53,26 +70,20 @@ describe('rdme openapi', () => {
5370
.basicAuth({ user: key })
5471
.reply(201, { _id: 1 }, { location: exampleRefLocation });
5572

56-
return openapi
57-
.run({
73+
await expect(
74+
openapi.run({
5875
spec: require.resolve(`@readme/oas-examples/${specVersion}/${format}/petstore.${format}`),
5976
key,
6077
version,
6178
})
62-
.then(() => {
63-
expect(console.log).toHaveBeenCalledTimes(1);
79+
).resolves.toBe(successfulUpload);
6480

65-
const output = getCommandOutput();
66-
expect(output).not.toMatch(/we found swagger.json/i);
67-
expect(output).toMatch(/successfully uploaded/);
68-
expect(output).toMatch(exampleRefLocation);
69-
expect(output).toMatch(/to update your openapi or swagger definition/i);
81+
expect(console.info).toHaveBeenCalledTimes(0);
7082

71-
mock.done();
72-
});
83+
return mock.done();
7384
});
7485

75-
it('should discover and upload an API definition if none is provided', () => {
86+
it('should discover and upload an API definition if none is provided', async () => {
7687
promptHandler.createOasPrompt.mockResolvedValue({ option: 'create' });
7788

7889
const mock = nock(config.host)
@@ -95,18 +106,15 @@ describe('rdme openapi', () => {
95106
// to break.
96107
fs.copyFileSync(require.resolve('@readme/oas-examples/2.0/json/petstore.json'), './swagger.json');
97108

98-
return openapi.run({ key }).then(() => {
99-
expect(console.log).toHaveBeenCalledTimes(2);
109+
await expect(openapi.run({ key })).resolves.toBe(successfulUpload);
100110

101-
const output = getCommandOutput();
102-
expect(output).toMatch(/we found swagger.json/i);
103-
expect(output).toMatch(/successfully uploaded/);
104-
expect(output).toMatch(exampleRefLocation);
105-
expect(output).toMatch(/to update your openapi or swagger definition/i);
111+
expect(console.info).toHaveBeenCalledTimes(1);
106112

107-
fs.unlinkSync('./swagger.json');
108-
return mock.done();
109-
});
113+
const output = getCommandOutput();
114+
expect(output).toBe(chalk.yellow('We found swagger.json and are attempting to upload it.'));
115+
116+
fs.unlinkSync('./swagger.json');
117+
return mock.done();
110118
});
111119
});
112120

@@ -118,69 +126,73 @@ describe('rdme openapi', () => {
118126
['OpenAPI 3.0', 'yaml', '3.0'],
119127
['OpenAPI 3.1', 'json', '3.1'],
120128
['OpenAPI 3.1', 'yaml', '3.1'],
121-
])('should support updating a %s definition (format: %s)', (_, format, specVersion) => {
129+
])('should support updating a %s definition (format: %s)', async (_, format, specVersion) => {
122130
const mock = nock(config.host)
123131
.put(`/api/v1/api-specification/${id}`, body => body.match('form-data; name="spec"'))
124132
.basicAuth({ user: key })
125-
.reply(201, { body: '{ id: 1 }' });
133+
.reply(201, { _id: 1 }, { location: exampleRefLocation });
126134

127-
return openapi
128-
.run({
135+
await expect(
136+
openapi.run({
129137
spec: require.resolve(`@readme/oas-examples/${specVersion}/${format}/petstore.${format}`),
130138
key,
131139
id,
132140
version,
133141
})
134-
.then(() => {
135-
mock.done();
136-
});
142+
).resolves.toBe(successfulUpdate);
143+
144+
return mock.done();
137145
});
138146

139-
it('should still support `token`', () => {
147+
it('should still support `token`', async () => {
140148
const mock = nock(config.host)
141149
.put(`/api/v1/api-specification/${id}`, body => body.match('form-data; name="spec"'))
142150
.basicAuth({ user: key })
143-
.reply(201, { id: 1 }, { location: exampleRefLocation });
151+
.reply(201, { _id: 1 }, { location: exampleRefLocation });
144152

145-
return openapi
146-
.run({ spec: require.resolve('@readme/oas-examples/3.1/json/petstore.json'), token: `${key}-${id}`, version })
147-
.then(() => {
148-
expect(console.warn).toHaveBeenCalledTimes(2);
149-
expect(console.log).toHaveBeenCalledTimes(1);
153+
await expect(
154+
openapi.run({
155+
spec: require.resolve('@readme/oas-examples/3.1/json/petstore.json'),
156+
token: `${key}-${id}`,
157+
version,
158+
})
159+
).resolves.toBe(successfulUpdate);
150160

151-
const output = getCommandOutput();
161+
expect(console.warn).toHaveBeenCalledTimes(2);
162+
expect(console.info).toHaveBeenCalledTimes(0);
152163

153-
expect(output).toMatch(/The `--token` option has been deprecated/i);
164+
const output = getCommandOutput();
165+
166+
expect(output).toMatch(/The `--token` option has been deprecated/i);
154167

155-
mock.done();
156-
});
168+
return mock.done();
157169
});
158170

159-
it('should return warning if providing `id` and `version`', () => {
171+
it('should return warning if providing `id` and `version`', async () => {
160172
const mock = nock(config.host)
161173
.put(`/api/v1/api-specification/${id}`, body => body.match('form-data; name="spec"'))
162174
.basicAuth({ user: key })
163-
.reply(201, { id: 1 }, { location: exampleRefLocation });
175+
.reply(201, { _id: 1 }, { location: exampleRefLocation });
164176

165-
return openapi
166-
.run({ spec: require.resolve('@readme/oas-examples/3.1/json/petstore.json'), key, id, version })
167-
.then(() => {
168-
expect(console.warn).toHaveBeenCalledTimes(1);
169-
expect(console.log).toHaveBeenCalledTimes(1);
177+
await expect(
178+
openapi.run({ spec: require.resolve('@readme/oas-examples/3.1/json/petstore.json'), key, id, version })
179+
).resolves.toBe(successfulUpdate);
170180

171-
const output = getCommandOutput();
181+
expect(console.warn).toHaveBeenCalledTimes(1);
182+
expect(console.info).toHaveBeenCalledTimes(0);
172183

173-
expect(output).toMatch(/the `--version` option will be ignored/i);
184+
const output = getCommandOutput();
185+
186+
expect(output).toMatch(/the `--version` option will be ignored/i);
174187

175-
mock.done();
176-
});
188+
return mock.done();
177189
});
178190
});
179191

180192
describe('versioning', () => {
181193
it.todo('should return a 404 if version flag not found');
182194

183-
it('should request a version list if version is not found', () => {
195+
it('should request a version list if version is not found', async () => {
184196
promptHandler.generatePrompts.mockResolvedValue({
185197
option: 'create',
186198
newVersion: '1.0.1',
@@ -200,18 +212,15 @@ describe('rdme openapi', () => {
200212
.basicAuth({ user: key })
201213
.reply(201, { _id: 1 }, { location: exampleRefLocation });
202214

203-
return openapi.run({ spec: require.resolve('@readme/oas-examples/2.0/json/petstore.json'), key }).then(() => {
204-
const output = getCommandOutput();
205-
expect(output).toMatch(/successfully uploaded/);
206-
expect(output).toMatch(exampleRefLocation);
207-
expect(output).toMatch(/to update your openapi or swagger definition/i);
215+
await expect(
216+
openapi.run({ spec: require.resolve('@readme/oas-examples/2.0/json/petstore.json'), key })
217+
).resolves.toBe(successfulUpload);
208218

209-
mock.done();
210-
});
219+
return mock.done();
211220
});
212221
});
213222

214-
it('should bundle and upload the expected content', () => {
223+
it('should bundle and upload the expected content', async () => {
215224
let requestBody = null;
216225
const mock = nock(config.host)
217226
.get('/api/v1/api-specification')
@@ -229,23 +238,20 @@ describe('rdme openapi', () => {
229238
.basicAuth({ user: key })
230239
.reply(201, { _id: 1 }, { location: exampleRefLocation });
231240

232-
return openapi.run({ spec: './__tests__/__fixtures__/ref-oas/petstore.json', key, version }).then(() => {
233-
expect(console.log).toHaveBeenCalledTimes(1);
241+
await expect(openapi.run({ spec: './__tests__/__fixtures__/ref-oas/petstore.json', key, version })).resolves.toBe(
242+
successfulUpload
243+
);
234244

235-
expect(requestBody).toMatchSnapshot();
245+
expect(console.info).toHaveBeenCalledTimes(0);
236246

237-
const output = getCommandOutput();
238-
expect(output).toMatch(/successfully uploaded/);
239-
expect(output).toMatch(exampleRefLocation);
240-
expect(output).toMatch(/to update your openapi or swagger definition/i);
247+
expect(requestBody).toMatchSnapshot();
241248

242-
mock.done();
243-
});
249+
return mock.done();
244250
});
245251

246252
describe('error handling', () => {
247-
it('should error if no api key provided', async () => {
248-
await expect(
253+
it('should error if no api key provided', () => {
254+
return expect(
249255
openapi.run({ spec: require.resolve('@readme/oas-examples/3.0/json/petstore.json') })
250256
).rejects.toThrow('No project API key provided. Please use `--key`.');
251257
});
@@ -258,17 +264,17 @@ describe('rdme openapi', () => {
258264

259265
await expect(openapi.run({ key, version })).rejects.toThrow(/We couldn't find an OpenAPI or Swagger definition./);
260266

261-
mock.done();
267+
return mock.done();
262268
});
263269

264-
it('should throw an error if an invalid OpenAPI 3.0 definition is supplied', async () => {
265-
await expect(
270+
it('should throw an error if an invalid OpenAPI 3.0 definition is supplied', () => {
271+
return expect(
266272
openapi.run({ spec: './__tests__/__fixtures__/invalid-oas.json', key, id, version })
267273
).rejects.toThrow('Token "Error" does not exist.');
268274
});
269275

270-
it('should throw an error if an invalid OpenAPI 3.1 definition is supplied', async () => {
271-
await expect(
276+
it('should throw an error if an invalid OpenAPI 3.1 definition is supplied', () => {
277+
return expect(
272278
openapi.run({ spec: './__tests__/__fixtures__/invalid-oas-3.1.json', key, id, version })
273279
).rejects.toMatchSnapshot();
274280
});
@@ -301,7 +307,7 @@ describe('rdme openapi', () => {
301307
})
302308
).rejects.toStrictEqual(new APIError(errorObject));
303309

304-
mock.done();
310+
return mock.done();
305311
});
306312

307313
it('should error if API errors', async () => {
@@ -329,7 +335,7 @@ describe('rdme openapi', () => {
329335
openapi.run({ spec: require.resolve('@readme/oas-examples/2.0/json/petstore.json'), key, version })
330336
).rejects.toStrictEqual(new APIError(errorObject));
331337

332-
mock.done();
338+
return mock.done();
333339
});
334340

335341
it('should error if API errors (generic upload error)', async () => {
@@ -349,7 +355,7 @@ describe('rdme openapi', () => {
349355
openapi.run({ spec: require.resolve('@readme/oas-examples/2.0/json/petstore.json'), key, version })
350356
).rejects.toStrictEqual(new Error('There was an error uploading!'));
351357

352-
mock.done();
358+
return mock.done();
353359
});
354360

355361
it('should error if API errors (request timeout)', async () => {
@@ -373,14 +379,14 @@ describe('rdme openapi', () => {
373379
)
374380
);
375381

376-
mock.done();
382+
return mock.done();
377383
});
378384
});
379385
});
380386

381387
describe('rdme swagger', () => {
382-
it('should run `rdme openapi`', async () => {
383-
await expect(swagger.run({ spec: '', key, id, version })).rejects.toThrow(
388+
it('should run `rdme openapi`', () => {
389+
return expect(swagger.run({ spec: '', key, id, version })).rejects.toThrow(
384390
"We couldn't find an OpenAPI or Swagger definition.\n\n" +
385391
'Run `rdme openapi ./path/to/api/definition` to upload an existing definition or `rdme oas init` to create a fresh one!'
386392
);

0 commit comments

Comments
 (0)