From bd1b5b34c1383b9be9fd8a01cc53f12caafcca36 Mon Sep 17 00:00:00 2001 From: Rhys Evans Date: Thu, 1 Apr 2021 15:45:53 +0100 Subject: [PATCH 1/7] Allow setting some schema parts as 'test only' --- .../data-accessors/__tests__/types.spec.js | 23 ++++-- .../tc-schema-sdk/lib/raw-data-wrapper.js | 78 ++++++++++++++++--- packages/tc-schema-sdk/sdk.js | 8 +- .../validation/json-schema/enums.js | 1 + .../validation/json-schema/type.js | 3 + 5 files changed, 92 insertions(+), 21 deletions(-) diff --git a/packages/tc-schema-sdk/data-accessors/__tests__/types.spec.js b/packages/tc-schema-sdk/data-accessors/__tests__/types.spec.js index 9896f19a2..dca4bca6e 100644 --- a/packages/tc-schema-sdk/data-accessors/__tests__/types.spec.js +++ b/packages/tc-schema-sdk/data-accessors/__tests__/types.spec.js @@ -1,6 +1,7 @@ const typeAccessor = jest.fn(); typeAccessor.mockImplementation(name => ({ - name: `${name} - retrieved`, + name: `${name}`, + retrieved: true, })); jest.doMock('../../data-accessors/type', () => { @@ -28,10 +29,12 @@ describe('get-types', () => { expect(types).toEqual([ { - name: 'Type1 - retrieved', + name: 'Type1', + retrieved: true, }, { - name: 'Type2 - retrieved', + name: 'Type2', + retrieved: true, }, ]); @@ -44,7 +47,7 @@ describe('get-types', () => { }); describe('with hierarchy', () => { - it('expects to be returned in order of type hiererchy', () => { + it('expects to be returned in order of type hierarchy', () => { const types = new SDK({ schemaData: { schema: { @@ -68,10 +71,12 @@ describe('get-types', () => { expect(types).toEqual([ { - name: 'Type2 - retrieved', + name: 'Type2', + retrieved: true, }, { - name: 'Type1 - retrieved', + name: 'Type1', + retrieved: true, }, ]); }); @@ -102,14 +107,16 @@ describe('get-types', () => { category1: { types: [ { - name: 'Type2 - retrieved', + name: 'Type2', + retrieved: true, }, ], }, category2: { types: [ { - name: 'Type1 - retrieved', + name: 'Type1', + retrieved: true, }, ], }, diff --git a/packages/tc-schema-sdk/lib/raw-data-wrapper.js b/packages/tc-schema-sdk/lib/raw-data-wrapper.js index 50d84e815..e8c414148 100644 --- a/packages/tc-schema-sdk/lib/raw-data-wrapper.js +++ b/packages/tc-schema-sdk/lib/raw-data-wrapper.js @@ -1,36 +1,83 @@ const deepFreeze = require('deep-freeze'); class RawDataWrapper { - constructor() { + constructor(options = {}) { + this.includeTestDefinitions = options.includeTestDefinitions; this.rawData = {}; } + filterTestProperties(obj = {}) { + if (this.includeTestDefinitions) { + return obj; + } + return Object.fromEntries( + Object.entries(obj).filter(([, { isTest }]) => !isTest), + ); + } + + filterTestItems(arr = []) { + if (this.includeTestDefinitions) { + return arr; + } + return arr.filter(({ isTest }) => !isTest); + } + + filterTestTypes(arr = []) { + if (this.includeTestDefinitions) { + return arr; + } + return this.filterTestItems(arr).map(obj => ({ + ...obj, + properties: this.filterTestProperties(obj.properties), + })); + } + checkDataExists() { if (!this.rawData.schema) { throw new Error(`Schema data does not exist. -Check that you have configured tc-schema-sdk correctly (see https://github.com/Financial-Times/treecreeper/tree/master/packages/tc-schema-sdk) +Check that you have configured biz-ops-schema correctly (see the README) and that you are using the correct refresh pattern for your environment and have waited for the first fetch of schema data to happen. -Often this error occurs because a method of tc-schema-sdk is called once at the -top level of a module; try calling it from within the function that uses the data -instead. + +If npm linking the schema locally, set \`updateMode: 'dev'\` `); } } getTypes() { this.checkDataExists(); - return this.rawData.schema.types; + return this.filterTestTypes(this.rawData.schema.types); } getRelationshipTypes() { this.checkDataExists(); - return this.rawData.schema.relationshipTypes || []; + return this.filterTestTypes(this.rawData.schema.relationshipTypes); } getTypeHierarchy() { this.checkDataExists(); - return this.rawData.schema.typeHierarchy; + if (!this.rawData.schema.typeHierarchy) { + return; + } + if (this.includeTestDefinitions) { + return this.rawData.schema.typeHierarchy; + } + const typeNames = this.filterTestItems(this.rawData.schema.types).map( + type => type.name, + ); + return Object.fromEntries( + Object.entries(this.rawData.schema.typeHierarchy || {}) + .map(([name, category]) => [ + name, + { + ...category, + types: category.types.filter(type => + typeNames.includes(type), + ), + }, + ]) + .filter(([, category]) => category.types.length), + ); } getStringPatterns() { @@ -40,7 +87,8 @@ instead. getEnums() { this.checkDataExists(); - return this.rawData.schema.enums; + // TODO - allow test enum values + return this.filterTestProperties(this.rawData.schema.enums); } getPrimitiveTypes() { @@ -54,7 +102,17 @@ instead. getAll() { this.checkDataExists(); - return this.rawData; + return { + schema: { + types: this.getTypes(), + relationshipTypes: this.getRelationshipTypes(), + stringPatterns: this.getStringPatterns(), + enums: this.getEnums(), + primitiveTypes: this.getPrimitiveTypes(), + typeHierarchy: this.getTypeHierarchy(), + }, + version: this.getVersion(), + }; } set(data) { diff --git a/packages/tc-schema-sdk/sdk.js b/packages/tc-schema-sdk/sdk.js index 6d722089d..b2331ce9b 100644 --- a/packages/tc-schema-sdk/sdk.js +++ b/packages/tc-schema-sdk/sdk.js @@ -13,17 +13,19 @@ const relationshipType = require('./data-accessors/relationship-type'); const { SchemaUpdater } = require('./lib/updater'); const utils = require('./lib/utils'); +const defaultOptions = { includeTestDefinitions: false }; + class SDK { - constructor(options) { + constructor(userOptions) { + const options = { ...defaultOptions, ...userOptions }; this.cache = new Cache(); - this.rawData = new RawDataWrapper(); + this.rawData = new RawDataWrapper(options); this.updater = new SchemaUpdater({ options, rawData: this.rawData, cache: this.cache, readYaml: this.readYaml, }); - this.TreecreeperUserError = TreecreeperUserError; this.getEnums = this.createEnrichedAccessor(enums); this.getPrimitiveTypes = this.createEnrichedAccessor(primitiveTypes); diff --git a/packages/tc-schema-validator/validation/json-schema/enums.js b/packages/tc-schema-validator/validation/json-schema/enums.js index e9bc8008f..a442c0146 100644 --- a/packages/tc-schema-validator/validation/json-schema/enums.js +++ b/packages/tc-schema-validator/validation/json-schema/enums.js @@ -6,6 +6,7 @@ const enumSchema = { type: 'object', properties: { description: { type: 'string' }, + isTest: { type: 'boolean' }, options: { if: { type: 'object', diff --git a/packages/tc-schema-validator/validation/json-schema/type.js b/packages/tc-schema-validator/validation/json-schema/type.js index f5029472d..f547944ae 100644 --- a/packages/tc-schema-validator/validation/json-schema/type.js +++ b/packages/tc-schema-validator/validation/json-schema/type.js @@ -37,6 +37,7 @@ const getPropertiesSchema = ({ forRelationships = false } = {}) => { const propertyDefSchema = { type: 'object', properties: { + isTest: { type: 'boolean' }, label: { type: 'string', not: { pattern: '[.!]\\s*$' } }, description: { type: 'string', pattern: '[.!?]\\s*$' }, type: { @@ -152,6 +153,7 @@ const typeSchema = { type: 'object', additionalProperties: false, properties: { + isTest: { type: 'boolean' }, name: typeName, description: { type: 'string' }, moreInformation: { type: 'string' }, @@ -209,6 +211,7 @@ const relationshipTypeSchema = { type: 'object', additionalProperties: false, properties: { + isTest: { type: 'boolean' }, name: typeName, from: fromOrTo, to: fromOrTo, From dade8d6a1a8a8dce985bb40c5d296d83d2929870 Mon Sep 17 00:00:00 2001 From: Rhys Evans Date: Thu, 1 Apr 2021 15:46:32 +0100 Subject: [PATCH 2/7] Allow deploying with test parts of schema --- packages/tc-schema-publisher/scripts/command.js | 5 +++++ packages/tc-schema-publisher/scripts/deploy.js | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) mode change 100644 => 100755 packages/tc-schema-publisher/scripts/command.js diff --git a/packages/tc-schema-publisher/scripts/command.js b/packages/tc-schema-publisher/scripts/command.js old mode 100644 new mode 100755 index 20d5447f2..64faa7bc9 --- a/packages/tc-schema-publisher/scripts/command.js +++ b/packages/tc-schema-publisher/scripts/command.js @@ -42,6 +42,11 @@ program 'S3 bucket name which you want to upload. (default: "process.env.TREECREEPER_SCHEMA_BUCKET")', process.env.TREECREEPER_SCHEMA_BUCKET, ) + .option( + '--include-test-definitions ', + 'Whether to include definitions intended only for the test environment in the release. (default: false))', + false, + ) .option('-E, --env ', 'specify publish environment', 'latest') .version(pkg.version) .action(action) diff --git a/packages/tc-schema-publisher/scripts/deploy.js b/packages/tc-schema-publisher/scripts/deploy.js index b86b161ef..5a0df1e72 100755 --- a/packages/tc-schema-publisher/scripts/deploy.js +++ b/packages/tc-schema-publisher/scripts/deploy.js @@ -6,7 +6,12 @@ const { SDK } = require('@financial-times/tc-schema-sdk'); const { sendSchemaToS3 } = require('..'); const deploy = async command => { - const { schemaDirectory, bucketName, env } = command; + const { + schemaDirectory, + bucketName, + env, + includeTestDefinitions, + } = command; try { if (!bucketName) { @@ -28,7 +33,7 @@ const deploy = async command => { if (!stat.isDirectory()) { throw new Error('schema directory is not a directory'); } - const schema = new SDK({ schemaDirectory }); + const schema = new SDK({ schemaDirectory, includeTestDefinitions }); await sendSchemaToS3(env, bucketName, schema); console.log('successfully deployed'); } catch (err) { From 045cf06bdd7a861ab55d55aa9ab804b6991eb1f4 Mon Sep 17 00:00:00 2001 From: Rhys Evans Date: Thu, 1 Apr 2021 15:46:42 +0100 Subject: [PATCH 3/7] Add tests for schema publishing --- .../scripts/__tests__/deploy-test.spec.js | 50 +++++++++++++++++++ .../scripts/__tests__/schema/enums.yaml | 6 +++ .../__tests__/schema/type-hierarchy.yaml | 5 ++ .../scripts/__tests__/schema/types/TypeA.yaml | 5 ++ .../scripts/__tests__/schema/types/TypeB.yaml | 11 ++++ 5 files changed, 77 insertions(+) create mode 100644 packages/tc-schema-publisher/scripts/__tests__/deploy-test.spec.js create mode 100644 packages/tc-schema-publisher/scripts/__tests__/schema/types/TypeB.yaml diff --git a/packages/tc-schema-publisher/scripts/__tests__/deploy-test.spec.js b/packages/tc-schema-publisher/scripts/__tests__/deploy-test.spec.js new file mode 100644 index 000000000..229644737 --- /dev/null +++ b/packages/tc-schema-publisher/scripts/__tests__/deploy-test.spec.js @@ -0,0 +1,50 @@ +const mockS3Instance = { + upload: jest.fn().mockReturnThis(), + promise: jest.fn(), +}; + +jest.mock('aws-sdk', () => { + return { S3: jest.fn(() => mockS3Instance) }; +}); + +const { deploy } = require('../deploy'); + +describe('tc-schema-sdk/deploy test', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('can deploy with test properties', async () => { + require('../deploy'); + + await deploy({ + schemaDirectory: `packages/tc-schema-publisher/scripts/__tests__/schema`, + bucketName: 'blah', + includeTestDefinitions: true, + env: 'latest', + }); + + expect(mockS3Instance.upload).toHaveBeenCalled(); + const body = mockS3Instance.upload.mock.calls[0][0].Body; + let content = ''; + body.on('data', chunk => { + content += chunk.toString('utf8'); + }); + await new Promise(res => { + body.on('end', res); + }); + const { schema } = JSON.parse(content); + expect(schema.types.length).toEqual(2); + expect(schema.types[0].name).toEqual('TypeA'); + expect(schema.types[1].name).toEqual('TypeB'); + expect(Object.keys(schema.types[0].properties)).toEqual([ + 'code', + 'stringPropertyA', + 'stringPropertyB', + ]); + expect(Object.keys(schema.enums)).toEqual(['AnEnum', 'ATestEnum']); + expect(Object.keys(schema.typeHierarchy)).toEqual(['prod', 'test']); + expect(schema.typeHierarchy.prod.types).toEqual(['TypeA']); + expect(schema.typeHierarchy.test.types).toEqual(['TypeB']); + }); +}); diff --git a/packages/tc-schema-publisher/scripts/__tests__/schema/enums.yaml b/packages/tc-schema-publisher/scripts/__tests__/schema/enums.yaml index 70401cfe6..e87b3508c 100644 --- a/packages/tc-schema-publisher/scripts/__tests__/schema/enums.yaml +++ b/packages/tc-schema-publisher/scripts/__tests__/schema/enums.yaml @@ -3,3 +3,9 @@ AnEnum: Another example enum options: First: First option +ATestEnum: + description: | + Another example enum + isTest: true + options: + First: First option diff --git a/packages/tc-schema-publisher/scripts/__tests__/schema/type-hierarchy.yaml b/packages/tc-schema-publisher/scripts/__tests__/schema/type-hierarchy.yaml index 46b2765f9..cbc7a66de 100644 --- a/packages/tc-schema-publisher/scripts/__tests__/schema/type-hierarchy.yaml +++ b/packages/tc-schema-publisher/scripts/__tests__/schema/type-hierarchy.yaml @@ -3,3 +3,8 @@ prod: description: Prod types types: - TypeA +test: + label: Test + description: Test types + types: + - TypeB diff --git a/packages/tc-schema-publisher/scripts/__tests__/schema/types/TypeA.yaml b/packages/tc-schema-publisher/scripts/__tests__/schema/types/TypeA.yaml index ee6977a2d..820d9de7d 100644 --- a/packages/tc-schema-publisher/scripts/__tests__/schema/types/TypeA.yaml +++ b/packages/tc-schema-publisher/scripts/__tests__/schema/types/TypeA.yaml @@ -12,3 +12,8 @@ properties: type: Word description: stringPropertyA description. label: stringPropertyA label + stringPropertyB: + type: Word + description: stringPropertyB description. + label: stringPropertyB label + isTest: true diff --git a/packages/tc-schema-publisher/scripts/__tests__/schema/types/TypeB.yaml b/packages/tc-schema-publisher/scripts/__tests__/schema/types/TypeB.yaml new file mode 100644 index 000000000..0507d2303 --- /dev/null +++ b/packages/tc-schema-publisher/scripts/__tests__/schema/types/TypeB.yaml @@ -0,0 +1,11 @@ +name: TypeB +description: type b +isTest: true +properties: + code: + type: Code + unique: true + canIdentify: true + description: Code description. + label: Code label + pattern: CODE From cae335e0da9db9cdb2124c246e39cb4f814e6d77 Mon Sep 17 00:00:00 2001 From: Rhys Evans Date: Tue, 6 Apr 2021 14:45:31 +0100 Subject: [PATCH 4/7] fix tests --- .../tc-api-express/__tests__/schema-polling-startup.spec.js | 2 +- .../tc-api-express/__tests__/schema-polling-updates.spec.js | 4 +++- packages/tc-schema-sdk/sdk.js | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/tc-api-express/__tests__/schema-polling-startup.spec.js b/packages/tc-api-express/__tests__/schema-polling-startup.spec.js index 5fe8b73a0..a308549e4 100644 --- a/packages/tc-api-express/__tests__/schema-polling-startup.spec.js +++ b/packages/tc-api-express/__tests__/schema-polling-startup.spec.js @@ -1,5 +1,4 @@ const fetch = require('node-fetch'); -const { getApp } = require('..'); describe('schema polling startup', () => { beforeAll(() => { @@ -14,6 +13,7 @@ describe('schema polling startup', () => { process.env.TEST_STARTUP = true; process.env.TREECREEPER_SCHEMA_URL = 'http://example.com'; fetch.mock('*', {}); + const { getApp } = require('..'); let initialised = false; const promiseOfApp = getApp({ schemaOptions: { updateMode: 'poll' } }); expect(initialised).toBe(false); diff --git a/packages/tc-api-express/__tests__/schema-polling-updates.spec.js b/packages/tc-api-express/__tests__/schema-polling-updates.spec.js index ce7a0482f..b1badb377 100644 --- a/packages/tc-api-express/__tests__/schema-polling-updates.spec.js +++ b/packages/tc-api-express/__tests__/schema-polling-updates.spec.js @@ -1,7 +1,8 @@ const fetch = require('node-fetch'); const schemaPublisher = require('@financial-times/tc-schema-publisher'); const request = require('supertest'); -const { getApp } = require('..'); + +let getApp; jest.useFakeTimers(); jest.mock('@financial-times/tc-schema-publisher', () => ({ @@ -84,6 +85,7 @@ describe('schema polling updates', () => { { overwriteRoutes: false }, ) .catch(200); + ({ getApp } = require('..')); app = await getApp({ republishSchemaPrefix: 'custom', republishSchema: true, diff --git a/packages/tc-schema-sdk/sdk.js b/packages/tc-schema-sdk/sdk.js index b2331ce9b..d2182e963 100644 --- a/packages/tc-schema-sdk/sdk.js +++ b/packages/tc-schema-sdk/sdk.js @@ -16,7 +16,7 @@ const utils = require('./lib/utils'); const defaultOptions = { includeTestDefinitions: false }; class SDK { - constructor(userOptions) { + constructor(userOptions = {}) { const options = { ...defaultOptions, ...userOptions }; this.cache = new Cache(); this.rawData = new RawDataWrapper(options); From 68de9b40dad72cab140af8f8fcc05cb6f81e6047 Mon Sep 17 00:00:00 2001 From: Rhys Evans Date: Tue, 6 Apr 2021 15:10:00 +0100 Subject: [PATCH 5/7] tests for only retrieving test properties from sdk --- .../__tests__/test-schema-properties.spec.js | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 packages/tc-schema-sdk/__tests__/test-schema-properties.spec.js diff --git a/packages/tc-schema-sdk/__tests__/test-schema-properties.spec.js b/packages/tc-schema-sdk/__tests__/test-schema-properties.spec.js new file mode 100644 index 000000000..4004c6666 --- /dev/null +++ b/packages/tc-schema-sdk/__tests__/test-schema-properties.spec.js @@ -0,0 +1,133 @@ +const {SDK} = require('../sdk') + +const schemaFixture = { + "types": [ + { + "name": "TypeA", + "description": "type a", + "properties": { + "code": { + "type": "Code", + "unique": true, + "canIdentify": true, + "description": "Code description.", + "label": "Code label", + "pattern": "CODE" + }, + "stringPropertyA": { + "type": "Word", + "description": "stringPropertyA description.", + "label": "stringPropertyA label" + }, + "stringPropertyB": { + "type": "Word", + "description": "stringPropertyB description.", + "label": "stringPropertyB label", + "isTest": true + } + } + }, + { + "name": "TypeB", + "description": "type b", + "isTest": true, + "properties": { + "code": { + "type": "Code", + "unique": true, + "canIdentify": true, + "description": "Code description.", + "label": "Code label", + "pattern": "CODE" + } + } + } + ], + "relationshipTypes": [], + "stringPatterns": { + "CODE": "^(?=.{2,64}$)[a-z0-9]+(?:-[a-z0-9]+)*$" + }, + "enums": { + "AnEnum": { + "description": "Another example enum\n", + "options": { + "First": "First option" + } + }, + "ATestEnum": { + "description": "Another example enum\n", + "isTest": true, + "options": { + "First": "First option" + } + } + }, + "primitiveTypes": { + "Code": { + "graphql": "String", + "component": "Text" + }, + "Word": { + "graphql": "String", + "component": "Text" + }, + "Document": { + "graphql": "String", + "component": "LargeText" + }, + "Url": { + "graphql": "String", + "component": "Text" + } + }, + "typeHierarchy": { + "prod": { + "label": "Prod", + "description": "Prod types", + "types": [ + "TypeA" + ] + }, + "test": { + "label": "Test", + "description": "Test types", + "types": [ + "TypeB" + ] + } + } + } + +describe('test schema properties',() => { + it('excludes test properties by default', async () => { + const schema = new SDK({ schemaData: { schema: schemaFixture }}) + await schema.ready() + expect(schema.getTypes().length).toEqual(1); + expect(schema.getTypes()[0].name).toEqual('TypeA'); + expect(Object.keys(schema.getTypes()[0].properties)).toEqual([ + 'code', + 'stringPropertyA', + ]); + expect(Object.keys(schema.getEnums())).toEqual(['AnEnum']); + expect(Object.keys(schema.getTypes({ grouped: true }))).toEqual(['prod']); + expect(schema.getTypes({ grouped: true }).prod.types[0].name).toEqual('TypeA'); + }) + + it('includes test properties on demand', async () => { + const schema = new SDK({ schemaData: { schema: schemaFixture }, includeTestDefinitions: true}) + await schema.ready() + expect(schema.getTypes().length).toEqual(2); + expect(schema.getTypes()[0].name).toEqual('TypeA'); + expect(schema.getTypes()[1].name).toEqual('TypeB'); + expect(Object.keys(schema.getTypes()[0].properties)).toEqual([ + 'code', + 'stringPropertyA', + 'stringPropertyB', + ]); + expect(Object.keys(schema.getEnums())).toEqual(['AnEnum', 'ATestEnum']); + expect(Object.keys(schema.getTypes({ grouped: true }))).toEqual(['prod', 'test']); + expect(schema.getTypes({ grouped: true }).prod.types[0].name).toEqual('TypeA'); + expect(schema.getTypes({ grouped: true }).test.types[0].name).toEqual('TypeB'); + }) + +}) From 5bf3b71e75f353813735a995d1ec79d99b8ce4d1 Mon Sep 17 00:00:00 2001 From: Rhys Evans Date: Tue, 6 Apr 2021 15:14:04 +0100 Subject: [PATCH 6/7] document isTest --- packages/tc-schema-sdk/README.md | 2 +- packages/tc-schema-validator/MODEL_SPECIFICATION.md | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/tc-schema-sdk/README.md b/packages/tc-schema-sdk/README.md index 5fc93e1e8..a715a6efd 100644 --- a/packages/tc-schema-sdk/README.md +++ b/packages/tc-schema-sdk/README.md @@ -43,7 +43,7 @@ The package exports an `init(options)` function, that takes the following option - `updateMode` - 'poll' or 'stale'. 'poll' will start polling on an interval for schema updates, whereas 'stale' will fetch whenever a user calls the sdk's `refresh()` method and the schema is older than the `ttl` - `logger` (default `console`) - choice of logger to use in the sdk - `version` - used to specify the version of the schema being used. Only used in tests - +- `includeTestDefinitions` - (default: `false`) a flag to indicate whether to use schema definitions that are flagged as test only using `isTest: true` One of `schemaDirectory`, `schemaData` or `schemaBaseUrl` must be defined. If `schemaBaseUrl` is defined, then `updateMode` must also be defined. ### Update APIs diff --git a/packages/tc-schema-validator/MODEL_SPECIFICATION.md b/packages/tc-schema-validator/MODEL_SPECIFICATION.md index 4f92d6a6d..7ae6fe197 100644 --- a/packages/tc-schema-validator/MODEL_SPECIFICATION.md +++ b/packages/tc-schema-validator/MODEL_SPECIFICATION.md @@ -24,6 +24,7 @@ Types are defined in individual files in `schema/types`. Add a `.yaml` file name | createPermissions | no | | An array listing the names of systems that are allowed to create instances of this type. If not specified, any system is allowed to | `- biz-ops-github-importer` | | minimumViableRecord | no | | An array listing the names of properties of this type that are considered particularly important. This information can then be used by other systems to take action to ensure this data is entered | `- delivereyTeam` | | inactiveRule | no | | Many types have an `isActive` property, which is used to specify whether a particular record is active. Some types may use different properties to define this, and may define an `inactiveRule` object defining one or more property names and the values they can take that denote they are inactive | `lifecycleStage: Decommissioned` | +| isTest | no | | Types that should only be defined in test environments can flag this by setting this flag | `isTest: true` | ### Property Definitions @@ -47,6 +48,8 @@ Each property definition is an object with the following properties | lockedBy | no | | Array of strings listing the client-ids that are allowed to edit the values stored in this property | | +| isTest | no | | Properties that should only be defined in test environments can flag this by setting this flag | `isTest: true` | + Note: All existing and any new properties, except for relationships, will automatically have the functionality to be filtered. ### Primitive types @@ -93,6 +96,8 @@ Sometimes it's useful to be able to annotate relationships with additional metad | to | yes | | Details of the end node of the relationship. An object with two properties, `type` and `hasMany`, specifying the type and cardinality of this end of the relationship | `{type: 'House', hasMany: false}` , `{type: 'Person', hasMany: true}` | | relationship | yes | | The name of the underlying neo4j relationship | `LIVES_IN` | | properties | no | | A map defining the names, types & labels etc. of properties to be stored on the relationship. See the (#property-definitions)[Property definitions section for more details]. | | +| isTest | no | | Relationship types that should only be defined in test environments can flag this by setting this flag | `isTest: true` | + To apply rich relationship definitions to a type, carry out a substititution similar to that below: @@ -182,6 +187,10 @@ StarRating: ... ``` + +Enums that should only be defined in test environments can flag this by setting the property `isTest: true` + + ### Add Description To better understand the enum options, you can give them a description From 2432ad600f32642d761d2643936a2f2392660f97 Mon Sep 17 00:00:00 2001 From: Rhys Evans Date: Tue, 6 Apr 2021 15:22:53 +0100 Subject: [PATCH 7/7] lint --- packages/tc-schema-sdk/README.md | 4 +- .../__tests__/test-schema-properties.spec.js | 233 +++++++++--------- .../MODEL_SPECIFICATION.md | 11 +- 3 files changed, 127 insertions(+), 121 deletions(-) diff --git a/packages/tc-schema-sdk/README.md b/packages/tc-schema-sdk/README.md index a715a6efd..1e2b90a5c 100644 --- a/packages/tc-schema-sdk/README.md +++ b/packages/tc-schema-sdk/README.md @@ -43,8 +43,8 @@ The package exports an `init(options)` function, that takes the following option - `updateMode` - 'poll' or 'stale'. 'poll' will start polling on an interval for schema updates, whereas 'stale' will fetch whenever a user calls the sdk's `refresh()` method and the schema is older than the `ttl` - `logger` (default `console`) - choice of logger to use in the sdk - `version` - used to specify the version of the schema being used. Only used in tests -- `includeTestDefinitions` - (default: `false`) a flag to indicate whether to use schema definitions that are flagged as test only using `isTest: true` -One of `schemaDirectory`, `schemaData` or `schemaBaseUrl` must be defined. If `schemaBaseUrl` is defined, then `updateMode` must also be defined. +- `includeTestDefinitions` - (default: `false`) a flag to indicate whether to use schema definitions that are flagged as test only using `isTest: true` + One of `schemaDirectory`, `schemaData` or `schemaBaseUrl` must be defined. If `schemaBaseUrl` is defined, then `updateMode` must also be defined. ### Update APIs diff --git a/packages/tc-schema-sdk/__tests__/test-schema-properties.spec.js b/packages/tc-schema-sdk/__tests__/test-schema-properties.spec.js index 4004c6666..be2a519ba 100644 --- a/packages/tc-schema-sdk/__tests__/test-schema-properties.spec.js +++ b/packages/tc-schema-sdk/__tests__/test-schema-properties.spec.js @@ -1,107 +1,103 @@ -const {SDK} = require('../sdk') +const { SDK } = require('../sdk'); const schemaFixture = { - "types": [ - { - "name": "TypeA", - "description": "type a", - "properties": { - "code": { - "type": "Code", - "unique": true, - "canIdentify": true, - "description": "Code description.", - "label": "Code label", - "pattern": "CODE" - }, - "stringPropertyA": { - "type": "Word", - "description": "stringPropertyA description.", - "label": "stringPropertyA label" - }, - "stringPropertyB": { - "type": "Word", - "description": "stringPropertyB description.", - "label": "stringPropertyB label", - "isTest": true - } - } - }, - { - "name": "TypeB", - "description": "type b", - "isTest": true, - "properties": { - "code": { - "type": "Code", - "unique": true, - "canIdentify": true, - "description": "Code description.", - "label": "Code label", - "pattern": "CODE" - } - } - } - ], - "relationshipTypes": [], - "stringPatterns": { - "CODE": "^(?=.{2,64}$)[a-z0-9]+(?:-[a-z0-9]+)*$" - }, - "enums": { - "AnEnum": { - "description": "Another example enum\n", - "options": { - "First": "First option" - } - }, - "ATestEnum": { - "description": "Another example enum\n", - "isTest": true, - "options": { - "First": "First option" - } - } - }, - "primitiveTypes": { - "Code": { - "graphql": "String", - "component": "Text" - }, - "Word": { - "graphql": "String", - "component": "Text" - }, - "Document": { - "graphql": "String", - "component": "LargeText" - }, - "Url": { - "graphql": "String", - "component": "Text" - } - }, - "typeHierarchy": { - "prod": { - "label": "Prod", - "description": "Prod types", - "types": [ - "TypeA" - ] - }, - "test": { - "label": "Test", - "description": "Test types", - "types": [ - "TypeB" - ] - } - } - } + types: [ + { + name: 'TypeA', + description: 'type a', + properties: { + code: { + type: 'Code', + unique: true, + canIdentify: true, + description: 'Code description.', + label: 'Code label', + pattern: 'CODE', + }, + stringPropertyA: { + type: 'Word', + description: 'stringPropertyA description.', + label: 'stringPropertyA label', + }, + stringPropertyB: { + type: 'Word', + description: 'stringPropertyB description.', + label: 'stringPropertyB label', + isTest: true, + }, + }, + }, + { + name: 'TypeB', + description: 'type b', + isTest: true, + properties: { + code: { + type: 'Code', + unique: true, + canIdentify: true, + description: 'Code description.', + label: 'Code label', + pattern: 'CODE', + }, + }, + }, + ], + relationshipTypes: [], + stringPatterns: { + CODE: '^(?=.{2,64}$)[a-z0-9]+(?:-[a-z0-9]+)*$', + }, + enums: { + AnEnum: { + description: 'Another example enum\n', + options: { + First: 'First option', + }, + }, + ATestEnum: { + description: 'Another example enum\n', + isTest: true, + options: { + First: 'First option', + }, + }, + }, + primitiveTypes: { + Code: { + graphql: 'String', + component: 'Text', + }, + Word: { + graphql: 'String', + component: 'Text', + }, + Document: { + graphql: 'String', + component: 'LargeText', + }, + Url: { + graphql: 'String', + component: 'Text', + }, + }, + typeHierarchy: { + prod: { + label: 'Prod', + description: 'Prod types', + types: ['TypeA'], + }, + test: { + label: 'Test', + description: 'Test types', + types: ['TypeB'], + }, + }, +}; -describe('test schema properties',() => { +describe('test schema properties', () => { it('excludes test properties by default', async () => { - const schema = new SDK({ schemaData: { schema: schemaFixture }}) - await schema.ready() + const schema = new SDK({ schemaData: { schema: schemaFixture } }); + await schema.ready(); expect(schema.getTypes().length).toEqual(1); expect(schema.getTypes()[0].name).toEqual('TypeA'); expect(Object.keys(schema.getTypes()[0].properties)).toEqual([ @@ -109,13 +105,20 @@ describe('test schema properties',() => { 'stringPropertyA', ]); expect(Object.keys(schema.getEnums())).toEqual(['AnEnum']); - expect(Object.keys(schema.getTypes({ grouped: true }))).toEqual(['prod']); - expect(schema.getTypes({ grouped: true }).prod.types[0].name).toEqual('TypeA'); - }) + expect(Object.keys(schema.getTypes({ grouped: true }))).toEqual([ + 'prod', + ]); + expect(schema.getTypes({ grouped: true }).prod.types[0].name).toEqual( + 'TypeA', + ); + }); - it('includes test properties on demand', async () => { - const schema = new SDK({ schemaData: { schema: schemaFixture }, includeTestDefinitions: true}) - await schema.ready() + it('includes test properties on demand', async () => { + const schema = new SDK({ + schemaData: { schema: schemaFixture }, + includeTestDefinitions: true, + }); + await schema.ready(); expect(schema.getTypes().length).toEqual(2); expect(schema.getTypes()[0].name).toEqual('TypeA'); expect(schema.getTypes()[1].name).toEqual('TypeB'); @@ -125,9 +128,15 @@ describe('test schema properties',() => { 'stringPropertyB', ]); expect(Object.keys(schema.getEnums())).toEqual(['AnEnum', 'ATestEnum']); - expect(Object.keys(schema.getTypes({ grouped: true }))).toEqual(['prod', 'test']); - expect(schema.getTypes({ grouped: true }).prod.types[0].name).toEqual('TypeA'); - expect(schema.getTypes({ grouped: true }).test.types[0].name).toEqual('TypeB'); - }) - -}) + expect(Object.keys(schema.getTypes({ grouped: true }))).toEqual([ + 'prod', + 'test', + ]); + expect(schema.getTypes({ grouped: true }).prod.types[0].name).toEqual( + 'TypeA', + ); + expect(schema.getTypes({ grouped: true }).test.types[0].name).toEqual( + 'TypeB', + ); + }); +}); diff --git a/packages/tc-schema-validator/MODEL_SPECIFICATION.md b/packages/tc-schema-validator/MODEL_SPECIFICATION.md index 7ae6fe197..e3b29a988 100644 --- a/packages/tc-schema-validator/MODEL_SPECIFICATION.md +++ b/packages/tc-schema-validator/MODEL_SPECIFICATION.md @@ -24,7 +24,7 @@ Types are defined in individual files in `schema/types`. Add a `.yaml` file name | createPermissions | no | | An array listing the names of systems that are allowed to create instances of this type. If not specified, any system is allowed to | `- biz-ops-github-importer` | | minimumViableRecord | no | | An array listing the names of properties of this type that are considered particularly important. This information can then be used by other systems to take action to ensure this data is entered | `- delivereyTeam` | | inactiveRule | no | | Many types have an `isActive` property, which is used to specify whether a particular record is active. Some types may use different properties to define this, and may define an `inactiveRule` object defining one or more property names and the values they can take that denote they are inactive | `lifecycleStage: Decommissioned` | -| isTest | no | | Types that should only be defined in test environments can flag this by setting this flag | `isTest: true` | +| isTest | no | | Types that should only be defined in test environments can flag this by setting this flag | `isTest: true` | ### Property Definitions @@ -48,7 +48,7 @@ Each property definition is an object with the following properties | lockedBy | no | | Array of strings listing the client-ids that are allowed to edit the values stored in this property | | -| isTest | no | | Properties that should only be defined in test environments can flag this by setting this flag | `isTest: true` | +| isTest | no | | Properties that should only be defined in test environments can flag this by setting this flag | `isTest: true` | Note: All existing and any new properties, except for relationships, will automatically have the functionality to be filtered. @@ -96,8 +96,7 @@ Sometimes it's useful to be able to annotate relationships with additional metad | to | yes | | Details of the end node of the relationship. An object with two properties, `type` and `hasMany`, specifying the type and cardinality of this end of the relationship | `{type: 'House', hasMany: false}` , `{type: 'Person', hasMany: true}` | | relationship | yes | | The name of the underlying neo4j relationship | `LIVES_IN` | | properties | no | | A map defining the names, types & labels etc. of properties to be stored on the relationship. See the (#property-definitions)[Property definitions section for more details]. | | -| isTest | no | | Relationship types that should only be defined in test environments can flag this by setting this flag | `isTest: true` | - +| isTest | no | | Relationship types that should only be defined in test environments can flag this by setting this flag | `isTest: true` | To apply rich relationship definitions to a type, carry out a substititution similar to that below: @@ -187,9 +186,7 @@ StarRating: ... ``` - -Enums that should only be defined in test environments can flag this by setting the property `isTest: true` - +Enums that should only be defined in test environments can flag this by setting the property `isTest: true` ### Add Description