diff --git a/CHANGELOG.md b/CHANGELOG.md index 195393338..bb151fb38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed +* Converted the standalone app-directory specification test from "src/app-directory/specification/test/" into a proper Jest test that runs as part of CI. ([#1720](https://github.com/finos/FDC3/pull/1720)) * Fix for channel change listeners not sending addEventListenerRequests ([#1606](https://github.com/finos/FDC3/pull/1606)) * When adding a listener on the current channel, the payload.channelId should be null ([#1611](https://github.com/finos/FDC3/pull/1611)) * Increased FDC3 Conformance Test WindowCloseWaitTime to 2000 (from 1000). ([#1586](https://github.com/finos/FDC3/issues/1586)) @@ -73,18 +74,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Added .NET docs for Events to API reference. ([#1441](https://github.com/finos/FDC3/pull/1441)) * Setup package publishing for mono-repo packages. ([#1520](https://github.com/finos/FDC3/pull/1520)) * Implementation PR for FDC3 for the Web ([#896](https://github.com/finos/FDC3/pull/896)) - - resolves ([#1209](https://github.com/finos/FDC3/issues/1209)) - - resolves ([#1297](https://github.com/finos/FDC3/issues/1297)) - - resolves ([#1429](https://github.com/finos/FDC3/issues/1429)) - - resolves ([#1430](https://github.com/finos/FDC3/issues/1430)) - - resolves ([#1431](https://github.com/finos/FDC3/issues/1431)) - - resolves ([#1432](https://github.com/finos/FDC3/issues/1432)) - - resolves ([#1433](https://github.com/finos/FDC3/issues/1433)) - - resolves ([#1468](https://github.com/finos/FDC3/issues/1468)) - - resolves ([#810](https://github.com/finos/FDC3/issues/810)) - - resolves ([#832](https://github.com/finos/FDC3/issues/832)) - - resolves ([#1487](https://github.com/finos/FDC3/issues/1487)) - - resolves ([#1488](https://github.com/finos/FDC3/issues/1488)) + * resolves ([#1209](https://github.com/finos/FDC3/issues/1209)) + * resolves ([#1297](https://github.com/finos/FDC3/issues/1297)) + * resolves ([#1429](https://github.com/finos/FDC3/issues/1429)) + * resolves ([#1430](https://github.com/finos/FDC3/issues/1430)) + * resolves ([#1431](https://github.com/finos/FDC3/issues/1431)) + * resolves ([#1432](https://github.com/finos/FDC3/issues/1432)) + * resolves ([#1433](https://github.com/finos/FDC3/issues/1433)) + * resolves ([#1468](https://github.com/finos/FDC3/issues/1468)) + * resolves ([#810](https://github.com/finos/FDC3/issues/810)) + * resolves ([#832](https://github.com/finos/FDC3/issues/832)) + * resolves ([#1487](https://github.com/finos/FDC3/issues/1487)) + * resolves ([#1488](https://github.com/finos/FDC3/issues/1488)) * Adjusted reference Desktop Agent implementation for FDC3 for Web to open a new app instance when raiseIntent is called with an appId but no instanceId ([#1556](https://github.com/finos/FDC3/pull/1556)) ### Changed @@ -111,7 +112,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Removed the `version` field from `IntentResolution` as there are no version fields for intents in the FDC3 API definitions and hence the field has no purpose. ([#1170](https://github.com/finos/FDC3/pull/1170)) * Fixed error in the Client-side example from `PrivateChannel` and `addIntentListener` by correcting `id.symbol` to `id.ticker` to align with the `fdc3.instrument` context. ([#1314](https://github.com/finos/FDC3/pull/1314)) * Added missing `resultType` argument to `findIntent` agent request in the Bridging Schema. ([#1154](https://github.com/finos/FDC3/pull/1154)) -* Added missing `resultType` argument to `findIntentByContext` agent request in the Bridging Schema. ([#1212](https://github.com/finos/FDC3/pull/1212)) +* Added missing `resultType` argument to `findIntentByContext` agent request in the Bridging Schema. ([#1212](https://github.com/finos/FDC3/pull/1212)) * Added missing id and name fields from the context base schema to respective context schemas (`Contact`, `ContactList`, `Country`, `InstrumentList`, `OrderList`, `Organization`, `Portfolio`, `Position`, `TradeList`). ([#1360](https://github.com/finos/FDC3/pull/1360)) * Revised FDC3 charter to include well-known language from the FDC3 introduction, better describe FDC3's scope, focus on financial applications, update application types, etc. ([#1079](https://github.com/finos/FDC3/pull/1079)) * Ensured that `PrivateChannelEvent` extends `ApiEvent` in both sourcecode and documentation. ([#1474](https://github.com/finos/FDC3/pull/1474)) @@ -133,7 +134,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added * Added `CreateInteraction` intent. To be used when a user wants to record an interaction into a system. New context `Interaction` also introduced. An interaction might be a call, IM, email, a meeting (physical or virtual) or the preparation of some specialist data. ([#747](https://github.com/finos/FDC3/pull/747)) -* Added `TransactionResult` context. A context type representing the result of a transaction initiated via FDC3. Its purpose is to provide a status and message (where needed) for the transaction and MAY wrap a returned context object. ([#761] (https://github.com/finos/FDC3/pull/761)) +* Added `TransactionResult` context. A context type representing the result of a transaction initiated via FDC3. Its purpose is to provide a status and message (where needed) for the transaction and MAY wrap a returned context object. ([#761](https://github.com/finos/FDC3/pull/761)) * Added a `MalformedContext` error to the `OpenError`, `ChannelError` and `ResolveError` enumerations, to be used when `broadcast`, `open`, `findIntents`, `raiseIntents`, and other related functions are passed an invalid context Object. ([#972](https://github.com/finos/FDC3/pull/972)) * Added error examples to the /v2 App Directory API routes ([#973](https://github.com/finos/FDC3/pull/973)) * Added a `SendChatMessage` intent to be used when a user wants to send a message to an existing chat room. ([#794](https://github.com/finos/FDC3/pull/794)) diff --git a/packages/fdc3-standard/package.json b/packages/fdc3-standard/package.json index 708561c7d..c9094357c 100644 --- a/packages/fdc3-standard/package.json +++ b/packages/fdc3-standard/package.json @@ -36,6 +36,7 @@ "@finos/fdc3-schema": "2.2.2-beta.1" }, "devDependencies": { + "@apidevtools/swagger-parser": "^10.1.1", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.19.0", "@typescript-eslint/eslint-plugin": "^8.18.2", @@ -46,6 +47,11 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-jsx-a11y": "^6.10.0", "globals": "^15.14.0", + "jest": "29.7.0", + "jest-environment-jsdom": "29.7.0", + "jest-junit": "^16.0.0", + "jest-mock-extended": "3.0.5", + "jsonschema": "^1.4.0", "prettier": "3.4.1", "quicktype": "23.0.78", "rimraf": "^6.0.1", diff --git a/packages/fdc3-standard/src/app-directory/specification/appd.schema.json b/packages/fdc3-standard/src/app-directory/specification/appd.schema.json index b4348c4be..6e3161ef2 100644 --- a/packages/fdc3-standard/src/app-directory/specification/appd.schema.json +++ b/packages/fdc3-standard/src/app-directory/specification/appd.schema.json @@ -656,7 +656,7 @@ }, "LaunchDetails": { "description": "The type specific launch details of the application. These details are intended to be vendor-agnostic and MAY be duplicated or overridden by details provided in the hostManifests object for a specific host.", - "oneOf": [ + "anyOf": [ { "$ref": "#/components/schemas/WebAppDetails" }, diff --git a/packages/fdc3-standard/src/app-directory/specification/test/index.js b/packages/fdc3-standard/src/app-directory/specification/test/index.js deleted file mode 100644 index c1fc58323..000000000 --- a/packages/fdc3-standard/src/app-directory/specification/test/index.js +++ /dev/null @@ -1,46 +0,0 @@ -import SwaggerParser from '@apidevtools/swagger-parser'; -import { Validator } from 'jsonschema'; -import { strict as assert } from 'assert'; -import { readFile } from 'fs/promises'; - -const exampleApplication1 = JSON.parse( - await readFile(new URL('../examples/application/myApplication.json', import.meta.url)) -); -const exampleApplication2 = JSON.parse( - await readFile(new URL('../examples/application/fdc3-workbench.json', import.meta.url)) -); - -(async () => { - try { - const api = await SwaggerParser.validate('../appd.schema.json'); - - console.log(`API name: ${api.info.title}, Version: ${api.info.version}`); - - const applicationSchema = api.components.schemas.Application; - - console.log('Setting up the validator...'); - const v = new Validator(); - - console.log('\nValidating the first example: myApplication.json'); - const validatorResult1 = v.validate(exampleApplication1, applicationSchema); - - assert( - validatorResult1.valid, - `The example application definition does not comply with the Application schema: ${validatorResult1.errors}` - ); - - console.log('Successfully validated the specification and the first example application definition!'); - - console.log('\nValidating the second example: fdc3-workbench.json'); - const validatorResult2 = v.validate(exampleApplication2, applicationSchema); - - assert( - validatorResult2.valid, - `The example application definition does not comply with the Application schema: ${validatorResult2.errors}` - ); - - console.log('Successfully validated the specification and the second example application definition!'); - } catch (error) { - console.log(error.message || error); - } -})(); diff --git a/packages/fdc3-standard/src/app-directory/specification/test/package-lock.json b/packages/fdc3-standard/src/app-directory/specification/test/package-lock.json deleted file mode 100644 index 7160bcbb9..000000000 --- a/packages/fdc3-standard/src/app-directory/specification/test/package-lock.json +++ /dev/null @@ -1,250 +0,0 @@ -{ - "name": "app-directory-specification-test", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "app-directory-specification-test", - "version": "1.0.0", - "license": "Apache-2.0", - "dependencies": { - "@apidevtools/swagger-parser": "^10.1.1", - "jsonschema": "^1.4.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.7.2", - "integrity": "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==", - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.15", - "js-yaml": "^4.1.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/philsturgeon" - } - }, - "node_modules/@apidevtools/openapi-schemas": { - "version": "2.1.0", - "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/@apidevtools/swagger-methods": { - "version": "3.0.2", - "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==" - }, - "node_modules/@apidevtools/swagger-parser": { - "version": "10.1.1", - "integrity": "sha512-u/kozRnsPO/x8QtKYJOqoGtC4kH6yg1lfYkB9Au0WhYB0FNLpyFusttQtvhlwjtG3rOwiRz4D8DnnXa8iEpIKA==", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "11.7.2", - "@apidevtools/openapi-schemas": "^2.1.0", - "@apidevtools/swagger-methods": "^3.0.2", - "@jsdevtools/ono": "^7.1.3", - "ajv": "^8.17.1", - "ajv-draft-04": "^1.0.0", - "call-me-maybe": "^1.0.2" - }, - "peerDependencies": { - "openapi-types": ">=7" - } - }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" - }, - "node_modules/ajv": { - "version": "8.17.1", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-draft-04": { - "version": "1.0.0", - "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "peerDependencies": { - "ajv": "^8.5.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/call-me-maybe": { - "version": "1.0.2", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ] - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/jsonschema": { - "version": "1.4.0", - "integrity": "sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==", - "engines": { - "node": "*" - } - }, - "node_modules/openapi-types": { - "version": "9.1.0", - "integrity": "sha512-mhXh8QN8sbErlxfxBeZ/pzgvmDn443p8CXlxwGSi2bWANZAFvjLPI0PoGjqHW+JdBbXg6uvmvM81WXaweh/SVA==", - "peer": true - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - } - }, - "dependencies": { - "@apidevtools/json-schema-ref-parser": { - "version": "11.7.2", - "integrity": "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==", - "requires": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.15", - "js-yaml": "^4.1.0" - } - }, - "@apidevtools/openapi-schemas": { - "version": "2.1.0", - "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==" - }, - "@apidevtools/swagger-methods": { - "version": "3.0.2", - "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==" - }, - "@apidevtools/swagger-parser": { - "version": "10.1.1", - "integrity": "sha512-u/kozRnsPO/x8QtKYJOqoGtC4kH6yg1lfYkB9Au0WhYB0FNLpyFusttQtvhlwjtG3rOwiRz4D8DnnXa8iEpIKA==", - "requires": { - "@apidevtools/json-schema-ref-parser": "11.7.2", - "@apidevtools/openapi-schemas": "^2.1.0", - "@apidevtools/swagger-methods": "^3.0.2", - "@jsdevtools/ono": "^7.1.3", - "ajv": "^8.17.1", - "ajv-draft-04": "^1.0.0", - "call-me-maybe": "^1.0.2" - } - }, - "@jsdevtools/ono": { - "version": "7.1.3", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" - }, - "@types/json-schema": { - "version": "7.0.15", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" - }, - "ajv": { - "version": "8.17.1", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "requires": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - } - }, - "ajv-draft-04": { - "version": "1.0.0", - "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "requires": {} - }, - "argparse": { - "version": "2.0.1", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "call-me-maybe": { - "version": "1.0.2", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" - }, - "fast-deep-equal": { - "version": "3.1.3", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-uri": { - "version": "3.1.0", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==" - }, - "js-yaml": { - "version": "4.1.1", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "jsonschema": { - "version": "1.4.0", - "integrity": "sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==" - }, - "openapi-types": { - "version": "9.1.0", - "integrity": "sha512-mhXh8QN8sbErlxfxBeZ/pzgvmDn443p8CXlxwGSi2bWANZAFvjLPI0PoGjqHW+JdBbXg6uvmvM81WXaweh/SVA==", - "peer": true - }, - "require-from-string": { - "version": "2.0.2", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" - } - } -} diff --git a/packages/fdc3-standard/src/app-directory/specification/test/package.json b/packages/fdc3-standard/src/app-directory/specification/test/package.json deleted file mode 100644 index d3296be91..000000000 --- a/packages/fdc3-standard/src/app-directory/specification/test/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "app-directory-specification-test", - "version": "1.0.0", - "author": "Fintech Open Source Foundation (FINOS)", - "homepage": "https://fdc3.finos.org", - "repository": { - "type": "git", - "url": "https://github.com/finos/FDC3.git" - }, - "publishConfig": { - "tag": "latest" - }, - "type": "module", - "license": "Apache-2.0", - "main": "index.js", - "files": [ - "index.js", - "src" - ], - "engines": { - "node": ">=10" - }, - "scripts": { - "test": "node index.js" - }, - "dependencies": { - "@apidevtools/swagger-parser": "^10.1.1", - "jsonschema": "^1.4.0" - } -} diff --git a/packages/fdc3-standard/test/AppDirectory.test.ts b/packages/fdc3-standard/test/AppDirectory.test.ts new file mode 100644 index 000000000..c916cc511 --- /dev/null +++ b/packages/fdc3-standard/test/AppDirectory.test.ts @@ -0,0 +1,52 @@ +import SwaggerParser from '@apidevtools/swagger-parser'; +import { Validator } from 'jsonschema'; +import { readFileSync } from 'fs'; +import { join } from 'path'; + +// Get the directory path for loading schema and example files +const specificationDir = join(__dirname, '..', 'src', 'app-directory', 'specification'); + +describe('App Directory Schema Validation', () => { + let api: unknown; + let applicationSchema: unknown; + let validator: Validator; + + beforeAll(async () => { + // Parse and validate the OpenAPI schema + const schemaPath = join(specificationDir, 'appd.schema.json'); + const schema = JSON.parse(readFileSync(schemaPath, 'utf-8')); + api = await SwaggerParser.validate(schema); + applicationSchema = (api as { components: { schemas: { Application: unknown } } }).components.schemas.Application; + validator = new Validator(); + }); + + it('should have valid API name and version', () => { + const apiInfo = (api as { info: { title: string; version: string } }).info; + expect(apiInfo.title).toBeDefined(); + expect(apiInfo.version).toBeDefined(); + }); + + it('should validate myApplication.json example against the Application schema', () => { + const examplePath = join(specificationDir, 'examples', 'application', 'myApplication.json'); + const exampleApplication = JSON.parse(readFileSync(examplePath, 'utf-8')); + + const result = validator.validate(exampleApplication, applicationSchema); + + if (!result.valid) { + throw new Error(`Validation errors: ${JSON.stringify(result.errors, null, 2)}`); + } + expect(result.valid).toBe(true); + }); + + it('should validate fdc3-workbench.json example against the Application schema', () => { + const examplePath = join(specificationDir, 'examples', 'application', 'fdc3-workbench.json'); + const exampleApplication = JSON.parse(readFileSync(examplePath, 'utf-8')); + + const result = validator.validate(exampleApplication, applicationSchema); + + expect(result.valid).toBe(true); + if (!result.valid) { + console.error('Validation errors:', result.errors); + } + }); +});