Skip to content

dev: test schemas in ./src and ./schemas #4333

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions scripts/schema-test-coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ for schemaDir in schemas/v3* ; do
version=$(basename "$schemaDir")
echo $version

node scripts/schema-test-coverage.mjs $schemaDir/schema.yaml tests/$version/pass
node scripts/schema-test-coverage.mjs $schemaDir/schema.yaml tests/schemas/$version/pass

echo
done
done

echo src
node scripts/schema-test-coverage.mjs src/schemas/validation/schema.yaml tests/schemas/dev/pass
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
68 changes: 68 additions & 0 deletions tests/schemas/schema.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { readdirSync, readFileSync } from "node:fs";
import YAML from "yaml";
import { validate as validate30 } from "@hyperjump/json-schema/openapi-3-0";
import { validate as validate31, setMetaSchemaOutputFormat } from "@hyperjump/json-schema/openapi-3-1";
import { BASIC } from "@hyperjump/json-schema/experimental";
import { describe, test, expect } from "vitest";

import contentTypeParser from "content-type";
import { addMediaTypePlugin } from "@hyperjump/browser";
import { buildSchemaDocument } from "@hyperjump/json-schema/experimental";
import { validate } from "mdv";

addMediaTypePlugin("application/schema+yaml", {
parse: async (response) => {
const contentType = contentTypeParser.parse(response.headers.get("content-type") ?? "");
const contextDialectId = contentType.parameters.schema ?? contentType.parameters.profile;

const foo = YAML.parse(await response.text());
return buildSchemaDocument(foo, response.url, contextDialectId);
},
fileMatcher: (path) => path.endsWith(".yaml")
});

const parseYamlFromFile = (filePath) => {
const schemaYaml = readFileSync(filePath, "utf8");
return YAML.parse(schemaYaml, { prettyErrors: true });
};

setMetaSchemaOutputFormat(BASIC);

const SCHEMAS = [
{ schema: "./schemas/v3.0/schema.yaml", fixtures: "./tests/schemas/v3.0", validate: validate30 },
{ schema: "./schemas/v3.1/schema.yaml", fixtures: "./tests/schemas/v3.1" },
{ schema: "./src/schemas/validation/schema.yaml", fixtures: "./tests/schemas/dev" }
];


for (const s of SCHEMAS) {
const validate = s.validate || validate31;
const validateOpenApi = await validate(s.schema);
const folder = s.fixtures;

describe(folder, () => {
describe("Pass", () => {
readdirSync(`${folder}/pass`, { withFileTypes: true })
.filter((entry) => entry.isFile() && /\.yaml$/.test(entry.name))
.forEach((entry) => {
test(entry.name, () => {
const instance = parseYamlFromFile(`${folder}/pass/${entry.name}`);
const output = validateOpenApi(instance, BASIC);
expect(output).to.deep.equal({ valid: true });
});
});
});

describe("Fail", () => {
readdirSync(`${folder}/fail`, { withFileTypes: true })
.filter((entry) => entry.isFile() && /\.yaml$/.test(entry.name))
.forEach((entry) => {
test(entry.name, () => {
const instance = parseYamlFromFile(`${folder}/fail/${entry.name}`);
const output = validateOpenApi(instance, BASIC);
expect(output.valid).to.equal(false);
});
});
});
});
}
1 change: 1 addition & 0 deletions tests/schemas/v3.0/fail/empty.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# this example doesn't have any of the required fields
File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions tests/schemas/v3.1/fail/invalid_schema_types.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
openapi: 3.1.1

# this example shows invalid types for the schemaObject

info:
title: API
version: 1.0.0
components:
schemas:
invalid_null: null
invalid_number: 0
invalid_array: []

7 changes: 7 additions & 0 deletions tests/schemas/v3.1/fail/no_containers.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
openapi: 3.1.0

# this example should fail as there are no paths, components or webhooks containers (at least one of which must be present)

info:
title: API
version: 1.0.0
14 changes: 14 additions & 0 deletions tests/schemas/v3.1/fail/server_enum_empty.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
openapi: 3.1.0

# this example should fail as the server variable enum is empty, and so does not contain the default value

info:
title: API
version: 1.0.0
servers:
- url: https://example.com/{var}
variables:
var:
enum: []
default: a
components: {}
11 changes: 11 additions & 0 deletions tests/schemas/v3.1/fail/servers.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
openapi: 3.1.0

# this example should fail, as servers must be an array, not an object

info:
title: API
version: 1.0.0
paths: {}
servers:
url: /v1
description: Run locally.
8 changes: 8 additions & 0 deletions tests/schemas/v3.1/fail/unknown_container.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
openapi: 3.1.0

# this example should fail as overlays is not a valid top-level object/keyword

info:
title: API
version: 1.0.0
overlays: {}
6 changes: 6 additions & 0 deletions tests/schemas/v3.1/pass/comp_pathitems.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
openapi: 3.1.0
info:
title: API
version: 1.0.0
components:
pathItems: {}
6 changes: 6 additions & 0 deletions tests/schemas/v3.1/pass/info_summary.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
openapi: 3.1.0
info:
title: API
summary: My lovely API
version: 1.0.0
components: {}
9 changes: 9 additions & 0 deletions tests/schemas/v3.1/pass/license_identifier.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
openapi: 3.1.0
info:
title: API
summary: My lovely API
version: 1.0.0
license:
name: Apache
identifier: Apache-2.0
components: {}
49 changes: 49 additions & 0 deletions tests/schemas/v3.1/pass/mega.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
openapi: 3.1.0
info:
summary: My API's summary
title: My API
version: 1.0.0
license:
name: Apache 2.0
identifier: Apache-2.0
jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base
paths:
/:
get:
parameters: []
/{pathTest}: {}
webhooks:
myWebhook:
$ref: '#/components/pathItems/myPathItem'
description: Overriding description
components:
securitySchemes:
mtls:
type: mutualTLS
pathItems:
myPathItem:
post:
requestBody:
required: true
content:
'application/json':
schema:
type: object
properties:
type:
type: string
int:
type: integer
exclusiveMaximum: 100
exclusiveMinimum: 0
none:
type: 'null'
arr:
type: array
$comment: Array without items keyword
either:
type: ['string','null']
discriminator:
propertyName: type
x-extension: true
myArbitraryKeyword: true
5 changes: 5 additions & 0 deletions tests/schemas/v3.1/pass/minimal_comp.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
openapi: 3.1.0
info:
title: API
version: 1.0.0
components: {}
5 changes: 5 additions & 0 deletions tests/schemas/v3.1/pass/minimal_hooks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
openapi: 3.1.0
info:
title: API
version: 1.0.0
webhooks: {}
5 changes: 5 additions & 0 deletions tests/schemas/v3.1/pass/minimal_paths.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
openapi: 3.1.0
info:
title: API
version: 1.0.0
paths: {}
19 changes: 19 additions & 0 deletions tests/schemas/v3.1/pass/non-oauth-scopes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
openapi: 3.1.0
info:
title: Non-oAuth Scopes example
version: 1.0.0
paths:
/users:
get:
security:
- bearerAuth:
- 'read:users'
- 'public'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: jwt
description: 'note: non-oauth scopes are not defined at the securityScheme level'

7 changes: 7 additions & 0 deletions tests/schemas/v3.1/pass/path_no_response.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
openapi: 3.1.0
info:
title: API
version: 1.0.0
paths:
/:
get: {}
6 changes: 6 additions & 0 deletions tests/schemas/v3.1/pass/path_var_empty_pathitem.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
openapi: 3.1.0
info:
title: API
version: 1.0.0
paths:
/{var}: {}
55 changes: 55 additions & 0 deletions tests/schemas/v3.1/pass/schema.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
openapi: 3.1.0
info:
title: API
version: 1.0.0
paths: {}
components:
schemas:
model:
type: object
properties:
one:
description: type array
type:
- integer
- string
two:
description: type 'null'
type: "null"
three:
description: type array including 'null'
type:
- string
- "null"
four:
description: array with no items
type: array
five:
description: singular example
type: string
examples:
- exampleValue
six:
description: exclusiveMinimum true
exclusiveMinimum: 10
seven:
description: exclusiveMinimum false
minimum: 10
eight:
description: exclusiveMaximum true
exclusiveMaximum: 20
nine:
description: exclusiveMaximum false
maximum: 20
ten:
description: nullable string
type:
- string
- "null"
eleven:
description: x-nullable string
type:
- string
- "null"
twelve:
description: file/binary
10 changes: 10 additions & 0 deletions tests/schemas/v3.1/pass/servers.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
openapi: 3.1.0
info:
title: API
version: 1.0.0
paths: {}
servers:
- url: /v1
description: Run locally.
- url: https://production.com/v1
description: Run on production server.
14 changes: 14 additions & 0 deletions tests/schemas/v3.1/pass/valid_schema_types.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
openapi: 3.1.1

# this example shows that top-level schemaObjects MAY be booleans

info:
title: API
version: 1.0.0
components:
schemas:
anything_boolean: true
nothing_boolean: false
anything_object: {}
nothing_object: { not: {} }

35 changes: 35 additions & 0 deletions tests/schemas/v3.1/pass/webhook-example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
openapi: 3.1.0
info:
title: Webhook Example
version: 1.0.0
# Since OAS 3.1.0 the paths element isn't necessary. Now a valid OpenAPI Document can describe only paths, webhooks, or even only reusable components
webhooks:
# Each webhook needs a name
newPet:
# This is a Path Item Object, the only difference is that the request is initiated by the API provider
post:
requestBody:
description: Information about a new pet in the system
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
responses:
"200":
description: Return a 200 status to indicate that the data was received successfully

components:
schemas:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string

Loading