diff --git a/.github/workflows/schema-tests.yaml b/.github/workflows/schema-tests.yaml index eb39b414b0..7a3116936d 100644 --- a/.github/workflows/schema-tests.yaml +++ b/.github/workflows/schema-tests.yaml @@ -9,8 +9,7 @@ name: schema-test # # run this on push to any branch and creation of pull-requests -on: - push: {} +on: pull_request: {} workflow_dispatch: {} @@ -33,3 +32,5 @@ jobs: - name: Run tests run: npm run test + env: + BASE: ${{ github.event.pull_request.base.ref }} diff --git a/scripts/schema-test-coverage.mjs b/scripts/schema-test-coverage.mjs index 0b2050ea60..5ebaad8d22 100644 --- a/scripts/schema-test-coverage.mjs +++ b/scripts/schema-test-coverage.mjs @@ -1,10 +1,11 @@ +import { readFileSync } from "node:fs"; import { readdir, readFile } from "node:fs/promises"; import YAML from "yaml"; import { join } from "node:path"; import { argv } from "node:process"; -import { validate } from "@hyperjump/json-schema/draft-2020-12"; +import { registerSchema, validate } from "@hyperjump/json-schema/openapi-3-1"; import "@hyperjump/json-schema/draft-04"; -import { BASIC } from "@hyperjump/json-schema/experimental"; +import { BASIC, defineVocabulary } from "@hyperjump/json-schema/experimental"; /** * @import { EvaluationPlugin } from "@hyperjump/json-schema/experimental" @@ -45,7 +46,14 @@ class TestCoveragePlugin { this.allLocations = []; for (const schemaLocation in context.ast) { - if (schemaLocation === "metaData") { + if ( + schemaLocation === "metaData" || + // Do not require coverage of standard JSON Schema + schemaLocation.includes("json-schema.org") || + // Do not require coverage of default $dynamicAnchor + // schemas, as they are not expected to be reached + schemaLocation.endsWith("/schema/WORK-IN-PROGRESS#/$defs/schema") + ) { continue; } @@ -110,6 +118,25 @@ const runTests = async (schemaUri, testDirectory) => { }; }; +const parseYamlFromFile = (filePath) => { + const schemaYaml = readFileSync(filePath, "utf8"); + return YAML.parse(schemaYaml, { prettyErrors: true }); +}; + +const meta = parseYamlFromFile("./src/schemas/validation/meta.yaml"); +const oasBaseVocab = Object.keys(meta.$vocabulary)[0]; + +defineVocabulary(oasBaseVocab, { + "discriminator": "https://spec.openapis.org/oas/3.0/keyword/discriminator", + "example": "https://spec.openapis.org/oas/3.0/keyword/example", + "externalDocs": "https://spec.openapis.org/oas/3.0/keyword/externalDocs", + "xml": "https://spec.openapis.org/oas/3.0/keyword/xml" +}); + +registerSchema(meta); +registerSchema(parseYamlFromFile("./src/schemas/validation/dialect.yaml")); +registerSchema(parseYamlFromFile("./src/schemas/validation/schema.yaml")); + /////////////////////////////////////////////////////////////////////////////// const { allLocations, visitedLocations } = await runTests(argv[2], argv[3]); @@ -122,16 +149,13 @@ if (notCovered.length > 0) { const firstNotCovered = notCovered.slice(0, maxNotCovered); if (notCovered.length > maxNotCovered) firstNotCovered.push("..."); console.log(firstNotCovered); + process.exitCode = 1; } console.log( "Covered:", - visitedLocations.size, + (allLocations.length - notCovered.length), "of", allLocations.length, - "(" + Math.floor((visitedLocations.size / allLocations.length) * 100) + "%)", + "(" + Math.floor(((allLocations.length - notCovered.length) / allLocations.length) * 100) + "%)", ); - -if (visitedLocations.size != allLocations.length) { - process.exitCode = 1; -} \ No newline at end of file diff --git a/scripts/schema-test-coverage.sh b/scripts/schema-test-coverage.sh index 825a254e26..600199b907 100755 --- a/scripts/schema-test-coverage.sh +++ b/scripts/schema-test-coverage.sh @@ -6,13 +6,11 @@ [[ ! -e src/schemas ]] && exit 0 -branch=$(git branch --show-current) - echo echo "Schema Test Coverage" echo -node scripts/schema-test-coverage.mjs src/schemas/validation/schema.yaml tests/schema/pass +node scripts/schema-test-coverage.mjs src/schemas/validation/schema-base.yaml tests/schema/pass rc=$? -[[ "$branch" == "dev" ]] || exit $rc +[[ "$BASE" == "dev" ]] || exit $rc diff --git a/tests/schema/pass/json_schema_dialect.yaml b/tests/schema/pass/json_schema_dialect.yaml new file mode 100644 index 0000000000..ae0ed863b3 --- /dev/null +++ b/tests/schema/pass/json_schema_dialect.yaml @@ -0,0 +1,15 @@ +openapi: 3.1.0 +info: + summary: Testing jsonSchemaDialect + 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/WORK-IN-PROGRESS +components: + schemas: + WithDollarSchema: + $id: "locked-metaschema" + $schema: https://spec.openapis.org/oas/3.1/dialect/WORK-IN-PROGRESS +paths: {} diff --git a/tests/schema/pass/mega.yaml b/tests/schema/pass/mega.yaml index 8838c03a6d..98ce577dce 100644 --- a/tests/schema/pass/mega.yaml +++ b/tests/schema/pass/mega.yaml @@ -6,7 +6,6 @@ info: license: name: Apache 2.0 identifier: Apache-2.0 -jsonSchemaDialect: https://spec.openapis.org/oas/3.1/dialect/base paths: /: get: diff --git a/tests/schema/schema.test.mjs b/tests/schema/schema.test.mjs index 362ccc856c..4ba5924816 100644 --- a/tests/schema/schema.test.mjs +++ b/tests/schema/schema.test.mjs @@ -1,7 +1,7 @@ import { readdirSync, readFileSync } from "node:fs"; import YAML from "yaml"; -import { validate, setMetaSchemaOutputFormat } from "@hyperjump/json-schema/openapi-3-1"; -import { BASIC } from "@hyperjump/json-schema/experimental"; +import { registerSchema, validate, setMetaSchemaOutputFormat } from "@hyperjump/json-schema/openapi-3-1"; +import { BASIC, defineVocabulary } from "@hyperjump/json-schema/experimental"; import { describe, test, expect } from "vitest"; import contentTypeParser from "content-type"; @@ -26,7 +26,21 @@ const parseYamlFromFile = (filePath) => { setMetaSchemaOutputFormat(BASIC); -const validateOpenApi = await validate("./src/schemas/validation/schema.yaml"); +const meta = parseYamlFromFile("./src/schemas/validation/meta.yaml"); +const oasBaseVocab = Object.keys(meta.$vocabulary)[0]; + +defineVocabulary(oasBaseVocab, { + "discriminator": "https://spec.openapis.org/oas/3.0/keyword/discriminator", + "example": "https://spec.openapis.org/oas/3.0/keyword/example", + "externalDocs": "https://spec.openapis.org/oas/3.0/keyword/externalDocs", + "xml": "https://spec.openapis.org/oas/3.0/keyword/xml" +}); + +registerSchema(meta); +registerSchema(parseYamlFromFile("./src/schemas/validation/dialect.yaml")); +registerSchema(parseYamlFromFile("./src/schemas/validation/schema.yaml")); + +const validateOpenApi = await validate("./src/schemas/validation/schema-base.yaml"); const fixtures = './tests/schema'; describe("v3.1", () => {