Skip to content

Commit 20cc2e5

Browse files
committed
add integration tests
1 parent bcb906b commit 20cc2e5

File tree

7 files changed

+180
-33
lines changed

7 files changed

+180
-33
lines changed

lint.js

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -83,25 +83,28 @@ const command = async (specFile, cmd) => {
8383
buildLoaderOptions(jsonSchema, verbose),
8484
);
8585

86-
validator.validate(spec, buildValidatorOptions(skip, verbose), (err, _options) => {
87-
const { context, warnings, valid } = _options || err.options;
88-
89-
if (err && valid === false) {
90-
console.error(colors.red + 'Specification schema is invalid.' + colors.reset);
91-
console.error(formatSchemaError(err, context));
92-
process.exit(1);
93-
}
94-
95-
if (warnings.length) {
96-
console.error(colors.red + 'Specification contains lint errors: ' + warnings.length + colors.reset);
97-
console.warn(formatLintResults(warnings))
98-
process.exit(1);
99-
}
100-
101-
if (!cmd.quiet) {
102-
console.log(colors.green + 'Specification is valid, with 0 lint errors' + colors.reset)
103-
}
104-
process.exit(0);
86+
return new Promise((resolve, reject) => {
87+
validator.validate(spec, buildValidatorOptions(skip, verbose), (err, _options) => {
88+
const { context, warnings, valid } = _options || err.options;
89+
90+
if (err && valid === false) {
91+
console.error(colors.red + 'Specification schema is invalid.' + colors.reset);
92+
console.error(formatSchemaError(err, context));
93+
return reject();
94+
}
95+
96+
if (warnings.length) {
97+
console.error(colors.red + 'Specification contains lint errors: ' + warnings.length + colors.reset);
98+
console.warn(formatLintResults(warnings))
99+
return reject();
100+
}
101+
102+
if (!cmd.quiet) {
103+
console.log(colors.green + 'Specification is valid, with 0 lint errors' + colors.reset)
104+
}
105+
106+
return resolve();
107+
});
105108
});
106109
};
107110

resolve.js

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,23 @@ const command = async (file, cmd) => {
1818
const spec = await loader.readOrError(file, buildLoaderOptions(jsonSchema, verbose));
1919
const content = yaml.safeDump(spec, { lineWidth: -1 });
2020

21-
if (output) {
22-
fs.writeFile(output, content, 'utf8', err => {
23-
if (err && verbose) {
24-
console.error('Failed to write file: ' + err.message);
25-
process.exit(1);
26-
}
27-
28-
if (verbose) console.log('Resolved to ' + output);
29-
});
30-
return;
31-
}
32-
console.log(content);
21+
return new Promise((resolve, reject) => {
22+
if (output) {
23+
fs.writeFile(output, content, 'utf8', err => {
24+
if (err && verbose) {
25+
console.error('Failed to write file: ' + err.message);
26+
return reject();
27+
}
28+
29+
if (verbose) console.log('Resolved to ' + output);
30+
});
31+
32+
return resolve();
33+
}
34+
35+
console.log(content);
36+
return resolve();
37+
});
3338
};
3439

3540
const buildLoaderOptions = (jsonSchema, verbose) => {

speccy.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ program
2828
.option('-s, --skip [ruleName]', 'provide multiple rules to skip', collect, [])
2929
.option('-j, --json-schema', 'treat $ref like JSON Schema and convert to OpenAPI Schema Objects (default: false)')
3030
.option('-v, --verbose', 'increase verbosity')
31-
.action(lint.command);
31+
.action((specFile, cmd) => {
32+
lint.command(specFile, cmd)
33+
.then( () => { process.exit(0) } )
34+
.catch( () => { process.exit(1) } );
35+
});
3236

3337
program
3438
.command('resolve <file-or-url>')
@@ -37,7 +41,11 @@ program
3741
.option('-q, --quiet', 'reduce verbosity')
3842
.option('-j, --json-schema', 'treat $ref like JSON Schema and convert to OpenAPI Schema Objects (default: false)')
3943
.option('-v, --verbose', 'increase verbosity')
40-
.action(resolve.command);
44+
.action((file, cmd) => {
45+
resolve.command(file, cmd)
46+
.then( () => { process.exit(0) } )
47+
.catch( () => { process.exit(1) } );
48+
});
4149

4250
program
4351
.command('serve <file-or-url>')
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
openapi: 3.0.0
3+
info:
4+
contact:
5+
namex: Derp
6+
7+
version: 1.0.0
8+
title: Swagger 2.0 Without Scheme
9+
paths: {}
10+
tags:
11+
- name: Gym
12+
- name: Pokemon
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
openapi: 3.0.0
3+
info:
4+
version: 1.0.0
5+
title: Swagger 2.0 Without Scheme
6+
paths: {}
7+
tags:
8+
- name: Gym
9+
- name: Pokemon
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
openapi: 3.0.0
2+
servers:
3+
- url: 'http://petstore.swagger.io/v2'
4+
info:
5+
description: >-
6+
This is a sample server Petstore server. You can find out more about
7+
Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net,
8+
#swagger](http://swagger.io/irc/). For this sample, you can use the api key
9+
`special-key` to test the authorization filters.
10+
version: 1.0.0
11+
title: Swagger Petstore
12+
termsOfService: 'http://swagger.io/terms/'
13+
contact:
14+
15+
license:
16+
name: Apache 2.0
17+
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
18+
paths:
19+
/pet:
20+
post:
21+
tags:
22+
- pet
23+
summary: Add a new pet to the store
24+
description: ''
25+
operationId: addPet
26+
responses:
27+
'405':
28+
description: Invalid input
29+
security:
30+
- petstore_auth:
31+
- 'write:pets'
32+
- 'read:pets'
33+
requestBody:
34+
$ref: '#/components/requestBodies/Pet'

test/integration/lint.test.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
'use strict';
2+
3+
const lint = require('../../lint.js');
4+
5+
const commandConfig = {
6+
quiet: false,
7+
rules: [],
8+
skip: []
9+
};
10+
11+
beforeEach(() => {
12+
jest.resetAllMocks();
13+
});
14+
15+
describe('Lint command', () => {
16+
describe('properly handles scheme validation', () => {
17+
test('succesfully validates a valid spec', () => {
18+
expect.assertions(4);
19+
const logSpy = jest.spyOn(console, 'log');
20+
const warnSpy = jest.spyOn(console, 'warn');
21+
const errorSpy = jest.spyOn(console, 'error');
22+
23+
return lint.command('./test/fixtures/loader/openapi.yaml', commandConfig).then(() => {
24+
expect(logSpy).toBeCalledTimes(1);
25+
expect(logSpy.mock.calls[0][0]).toEqual('\x1b[32mSpecification is valid, with 0 lint errors\x1b[0m');
26+
expect(warnSpy).toBeCalledTimes(0);
27+
expect(errorSpy).toBeCalledTimes(0);
28+
});
29+
});
30+
31+
test('displays a validation error on invalid key', () => {
32+
expect.assertions(4);
33+
const logSpy = jest.spyOn(console, 'log');
34+
const warnSpy = jest.spyOn(console, 'warn');
35+
const errorSpy = jest.spyOn(console, 'error');
36+
37+
return lint.command('./test/fixtures/integration/invalid-key.yaml', commandConfig).catch(() => {
38+
expect(logSpy).toBeCalledTimes(0);
39+
expect(warnSpy).toBeCalledTimes(0);
40+
expect(errorSpy).toBeCalledTimes(2);
41+
expect(errorSpy).toHaveBeenCalledWith('\x1b[31mSpecification schema is invalid.\x1b[0m');
42+
});
43+
});
44+
45+
test('displays a validation error on missing reference', () => {
46+
expect.assertions(4);
47+
const logSpy = jest.spyOn(console, 'log');
48+
const warnSpy = jest.spyOn(console, 'warn');
49+
const errorSpy = jest.spyOn(console, 'error');
50+
51+
return lint.command('./test/fixtures/integration/missing-ref.yaml', commandConfig).catch(() => {
52+
expect(logSpy).toBeCalledTimes(0);
53+
expect(warnSpy).toBeCalledTimes(0);
54+
expect(errorSpy).toBeCalledTimes(2);
55+
expect(errorSpy).toHaveBeenCalledWith('\x1b[31mSpecification schema is invalid.\x1b[0m');
56+
});
57+
});
58+
});
59+
60+
describe('properly handles linter warnings', () => {
61+
test('displays a linting error on missing contact field', () => {
62+
expect.assertions(5);
63+
const logSpy = jest.spyOn(console, 'log');
64+
const warnSpy = jest.spyOn(console, 'warn');
65+
const errorSpy = jest.spyOn(console, 'error');
66+
67+
return lint.command('./test/fixtures/integration/missing-contact.yaml', commandConfig).catch(() => {
68+
expect(logSpy).toBeCalledTimes(0);
69+
expect(warnSpy).toBeCalledTimes(1);
70+
expect(errorSpy).toBeCalledTimes(1);
71+
expect(errorSpy.mock.calls[0][0]).toEqual('\x1b[31mSpecification contains lint errors: 1\x1b[0m');
72+
expect(warnSpy.mock.calls[0][0]).toContain('info-contact');
73+
});
74+
});
75+
});
76+
});

0 commit comments

Comments
 (0)