spectral
spectral copied to clipboard
Docs: How to use the JavaScript API with `extends`
User Story
As a user, I want to write tests for my Spectral rules, so I can be more confident that the rules work.
Further details
I want to write tests, similar to the below:
const { Spectral, isOpenApiv3, Document } = require('@stoplight/spectral-core');
const Parsers = require("@stoplight/spectral-parsers"); // make sure to install the package if you intend to use default parsers!
const { truthy } = require("@stoplight/spectral-functions"); // this has to be installed as well
const yaml = require('js-yaml')
const fs = require('fs')
const path = require('path')
const myDocument = new Document(
`---
responses:
'200':
description: ''`,
Parsers.Yaml,
"/my-file",
);
const spectral = new Spectral({});
var ruleset = {
extends: [
'spectral:oas'
]
}
spectral.setRuleset(ruleset);
spectral.run(myDocument).then(console.log);
However, this fails due to:
throw new Error('Provided ruleset is not an object');
^
Error: Provided ruleset is not an object
at assertValidRuleset (/home/jamie/workspaces/cddo/api-standards-linting/govuk-public-api-rules/node_modules/@stoplight/spectral-core/dist/ruleset/validation.js:94:15)
at new Ruleset (/home/jamie/workspaces/cddo/api-standards-linting/govuk-public-api-rules/node_modules/@stoplight/spectral-core/dist/ruleset/ruleset.js:32:49)
at /home/jamie/workspaces/cddo/api-standards-linting/govuk-public-api-rules/node_modules/@stoplight/spectral-core/dist/ruleset/ruleset.js:74:37
at Array.reduce (<anonymous>)
at new Ruleset (/home/jamie/workspaces/cddo/api-standards-linting/govuk-public-api-rules/node_modules/@stoplight/spectral-core/dist/ruleset/ruleset.js:61:99)
at Spectral.setRuleset (/home/jamie/workspaces/cddo/api-standards-linting/govuk-public-api-rules/node_modules/@stoplight/spectral-core/dist/spectral.js:72:73)
at Object.<anonymous> (/home/jamie/workspaces/cddo/api-standards-linting/govuk-public-api-rules/example.js:25:10)
I can't see it mentioned in the docs how to use extends
with the JS API.
Unfortunately the solution noted in https://github.com/stoplightio/spectral/issues/1151 doesn't work any more as there's no assets.json
available, nor does registerStaticAssets
.
Versions
"@stoplight/spectral-cli": "^6.1.0",
"@stoplight/json": "3.17.0",
"@stoplight/path": "1.3.2",
"@stoplight/spectral-core": "^1.5.1",
"@stoplight/spectral-parsers": "^1.0.1",
"@stoplight/spectral-ref-resolver": "1.0.1",
"@stoplight/spectral-ruleset-bundler": "^1.0.0",
"@stoplight/spectral-ruleset-migrator": "^1.5.0",
"@stoplight/spectral-rulesets": ">=1",
"@stoplight/spectral-runtime": "^1.1.0",
"@stoplight/types": "12.3.0",
Hey! One should do the following
const { oas } = require('@stoplight/spectral-rulesets');
var ruleset = {
extends: [oas]
};
Hope that helps. You are more than welcome to update the documentation!
Thanks! I've also been able to get this working with steps as documented in https://www.jvt.me/posts/2021/12/22/spectral-jest/:
// Apache 2.0
const { fetch } = require('@stoplight/spectral-runtime')
const { Spectral, Document } = require('@stoplight/spectral-core')
const Parsers = require('@stoplight/spectral-parsers')
const fs = require('fs')
const path = require('path')
// we need to add `dist/loader/node` as per convo on https://github.com/stoplightio/spectral/issues/1956#issuecomment-999643841
const { bundleAndLoadRuleset } = require('@stoplight/spectral-ruleset-bundler/dist/loader/node')
const retrieveRuleset = async (filePath) => {
return await bundleAndLoadRuleset(path.resolve(filePath), { fs, fetch })
}
const retrieveDocument = (filePath) => {
const resolved = path.resolve(path.join('test/testdata', filePath))
const body = fs.readFileSync(resolved, 'utf8')
return new Document(body, Parsers.Yaml, filePath)
}
const setupSpectral = async () => {
const ruleset = await retrieveRuleset('ruleset.yaml')
const spectral = new Spectral()
spectral.setRuleset(ruleset)
return spectral
}
module.exports = {
retrieveDocument,
setupSpectral
}
Would it be best for me to raise a PR to get the docs page updated so there's a bit more info in there?
Would it be best for me to raise a PR to get the docs page updated so there's a bit more info in there?
sure, that'd be awesome.
FWIW I read your article, it's nice.
Note that you may run into Cannot find module 'nimma/legacy' errors, which can be solved through Jest configuration, which can be seen in the jest.config.js in the sample repo.
It might be good to mention here that this should work out of the box in Jest 28. https://github.com/facebook/jest/issues/9771 There might be some other nice workarounds there too which you may want to link.
@P0lip extends: [oas]
doesn't typecheck, though it does work at runtime...
Type '{ documentationUrl: string; formats: Format<void>[]; aliases: { PathItem: string[]; OperationObject: string[]; }; rules: { 'operation-success-response': { description: string; recommended: boolean; given: string; then: { ...; }; }; ... 49 more ...; 'oas3-unused-component': { ...; }; }; }' is not assignable to type 'RulesetDefinition | [RulesetDefinition, FileRulesetSeverityDefinition]'.
Property 'extends' is missing in type '{ documentationUrl: string; formats: Format<void>[]; aliases: { PathItem: string[]; OperationObject: string[]; }; rules: { 'operation-success-response': { description: string; recommended: boolean; given: string; then: { ...; }; }; ... 49 more ...; 'oas3-unused-component': { ...; }; }; }' but required in type 'Readonly<{ documentationUrl?: string | undefined; description?: string | undefined; formats?: Formats<Format> | Format[] | undefined; parserOptions?: Partial<ParserOptions> | undefined; overrides?: RulesetOverridesDefinition | undefined; aliases?: RulesetAliasesDefinition | undefined; } & Readonly<...>>'.ts(2322)
types.d.ts(66, 5): 'extends' is declared here.
"@stoplight/spectral-core": "^1.18.0",
"@stoplight/spectral-rulesets": "^1.16.0",
"@stoplight/types": "^13.13.0",