@pdtf/schemas 3.2.1-13 → 3.2.1-15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +61 -4
- package/package.json +1 -1
- package/src/examples/v3/exampleCustomOverlay.json +55 -0
- package/src/examples/v3/exampleCustomOverlay2.json +93 -0
- package/src/examples/v3/exampleTransaction.json +7 -1
- package/src/schemas/v3/combined.json +27 -1
- package/src/schemas/v3/pdtf-transaction.json +30 -1
- package/src/schemas/v3/skeleton.json +5 -1
- package/src/tests/v3/transactionSchema.test.js +225 -0
package/index.js
CHANGED
|
@@ -61,14 +61,49 @@ const transactionSchemas = {
|
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
const combineMerge = (target, source, options) => {
|
|
64
|
+
// Special handling for 'required' arrays - combine them uniquely
|
|
65
|
+
if (target.some((item) => typeof item === "string")) {
|
|
66
|
+
return [...new Set([...target, ...source])];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// For other arrays, concatenate while preserving uniqueness for primitive values
|
|
70
|
+
if (!options.isMergeableObject(target[0])) {
|
|
71
|
+
return [...new Set([...target, ...source])];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Special handling for oneOf arrays - merge matching schemas based on discriminator
|
|
75
|
+
if (target[0]?.properties && source[0]?.properties) {
|
|
76
|
+
// Find a common discriminator property (a property with an enum)
|
|
77
|
+
const findDiscriminator = (schema) => {
|
|
78
|
+
const props = schema.properties;
|
|
79
|
+
return Object.keys(props).find((key) => Array.isArray(props[key]?.enum));
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const discriminator = findDiscriminator(target[0]);
|
|
83
|
+
if (discriminator) {
|
|
84
|
+
return target.map((targetSchema) => {
|
|
85
|
+
const targetEnum = targetSchema.properties?.[discriminator]?.enum || [];
|
|
86
|
+
const matchingSourceSchema = source.find((sourceSchema) => {
|
|
87
|
+
const sourceEnum =
|
|
88
|
+
sourceSchema.properties?.[discriminator]?.enum || [];
|
|
89
|
+
// Check if there's any overlap between the enum values
|
|
90
|
+
return sourceEnum.some((value) => targetEnum.includes(value));
|
|
91
|
+
});
|
|
92
|
+
if (matchingSourceSchema) {
|
|
93
|
+
return merge(targetSchema, matchingSourceSchema, options);
|
|
94
|
+
}
|
|
95
|
+
return targetSchema;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// For arrays of objects, merge by index and append remaining items
|
|
64
101
|
const destination = target.slice();
|
|
65
102
|
source.forEach((item, index) => {
|
|
66
103
|
if (typeof destination[index] === "undefined") {
|
|
67
104
|
destination[index] = options.cloneUnlessOtherwiseSpecified(item, options);
|
|
68
105
|
} else if (options.isMergeableObject(item)) {
|
|
69
106
|
destination[index] = merge(target[index], item, options);
|
|
70
|
-
} else if (target.indexOf(item) === -1) {
|
|
71
|
-
destination.push(item);
|
|
72
107
|
}
|
|
73
108
|
});
|
|
74
109
|
return destination;
|
|
@@ -84,7 +119,12 @@ const getTransactionSchema = (
|
|
|
84
119
|
if (!overlays || overlays.length < 1) return sourceSchema;
|
|
85
120
|
let mergedSchema = sourceSchema;
|
|
86
121
|
overlays.forEach((overlay) => {
|
|
87
|
-
|
|
122
|
+
// Handle both string keys and direct overlay objects
|
|
123
|
+
const overlaySchema =
|
|
124
|
+
typeof overlay === "string"
|
|
125
|
+
? overlaysMap[schemaId][overlay] || {}
|
|
126
|
+
: overlay;
|
|
127
|
+
|
|
88
128
|
mergedSchema = merge(mergedSchema, overlaySchema, {
|
|
89
129
|
customMerge: (key) => {
|
|
90
130
|
if (key === "enum") {
|
|
@@ -97,6 +137,23 @@ const getTransactionSchema = (
|
|
|
97
137
|
return mergedSchema;
|
|
98
138
|
};
|
|
99
139
|
|
|
140
|
+
// Add helper function to generate cache key
|
|
141
|
+
const generateOverlayKey = (overlays) => {
|
|
142
|
+
if (!overlays) return "";
|
|
143
|
+
return overlays
|
|
144
|
+
.map((overlay) => {
|
|
145
|
+
if (typeof overlay === "string") return overlay;
|
|
146
|
+
// Generate a simple hash of the object for caching
|
|
147
|
+
return JSON.stringify(overlay)
|
|
148
|
+
.split("")
|
|
149
|
+
.reduce((hash, char) => {
|
|
150
|
+
return ((hash << 5) - hash + char.charCodeAt(0)) | 0;
|
|
151
|
+
}, 0)
|
|
152
|
+
.toString(36);
|
|
153
|
+
})
|
|
154
|
+
.join(".");
|
|
155
|
+
};
|
|
156
|
+
|
|
100
157
|
const getValidator = (schemaId, overlays) => {
|
|
101
158
|
return getSubschemaValidator("", schemaId, overlays);
|
|
102
159
|
};
|
|
@@ -135,7 +192,7 @@ const isPathValid = (path, schemaId, overlays) => {
|
|
|
135
192
|
|
|
136
193
|
const getSubschemaValidator = (path, schemaId, overlays) => {
|
|
137
194
|
const subSchema = getSubschema(path, schemaId, overlays);
|
|
138
|
-
const overlayKey = (overlays
|
|
195
|
+
const overlayKey = generateOverlayKey(overlays);
|
|
139
196
|
// see if we can retrieve the schema by path, schemaId and overlays
|
|
140
197
|
const cacheKey = `${path}-${schemaId}-${overlayKey}`;
|
|
141
198
|
let validator = ajv.getSchema(cacheKey);
|
package/package.json
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://trust.propdata.org.uk/schemas/v3/overlays/custom.json",
|
|
4
|
+
"properties": {
|
|
5
|
+
"propertyPack": {
|
|
6
|
+
"customRef": "JKW",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"required": ["specialistIssues"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"specialistIssues": {
|
|
11
|
+
"customRef": "JKW.7",
|
|
12
|
+
"required": ["japaneseKnotweed"],
|
|
13
|
+
"properties": {
|
|
14
|
+
"japaneseKnotweed": {
|
|
15
|
+
"customRef": "JKW.7.8",
|
|
16
|
+
"discriminator": {
|
|
17
|
+
"propertyName": "yesNo"
|
|
18
|
+
},
|
|
19
|
+
"oneOf": [
|
|
20
|
+
{
|
|
21
|
+
"properties": {
|
|
22
|
+
"yesNo": {
|
|
23
|
+
"enum": ["No", "Not known"]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"properties": {
|
|
29
|
+
"yesNo": {
|
|
30
|
+
"enum": ["Yes"]
|
|
31
|
+
},
|
|
32
|
+
"managementPlanInPlace": {
|
|
33
|
+
"customRef": "JKW.7.8.2"
|
|
34
|
+
},
|
|
35
|
+
"attachments": {
|
|
36
|
+
"customRef": "JKW.7.8.3"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"required": ["managementPlanInPlace", "attachments"]
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"required": ["yesNo"],
|
|
43
|
+
"title": "Is the property affected by Japanese knotweed?",
|
|
44
|
+
"properties": {
|
|
45
|
+
"yesNo": {
|
|
46
|
+
"customRef": "JKW.7.8.1"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://trust.propdata.org.uk/schemas/v3/overlays/ta7.json",
|
|
4
|
+
"properties": {
|
|
5
|
+
"propertyPack": {
|
|
6
|
+
"macRef": "MAC",
|
|
7
|
+
"required": ["ownership"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"ownership": {
|
|
10
|
+
"macRef": "MAC.1",
|
|
11
|
+
"required": ["ownershipsToBeTransferred"],
|
|
12
|
+
"properties": {
|
|
13
|
+
"ownershipsToBeTransferred": {
|
|
14
|
+
"macRef": "MAC.1",
|
|
15
|
+
"items": {
|
|
16
|
+
"discriminator": {
|
|
17
|
+
"propertyName": "ownershipType"
|
|
18
|
+
},
|
|
19
|
+
"oneOf": [
|
|
20
|
+
{
|
|
21
|
+
"properties": {
|
|
22
|
+
"ownershipType": {
|
|
23
|
+
"enum": ["Leasehold"]
|
|
24
|
+
},
|
|
25
|
+
"leaseholdInformation": {
|
|
26
|
+
"required": ["contactDetails"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"contactDetails": {
|
|
29
|
+
"macRef": "MAC.4.1",
|
|
30
|
+
"required": ["contacts"],
|
|
31
|
+
"properties": {
|
|
32
|
+
"contacts": {
|
|
33
|
+
"macRef": "MAC.4.1",
|
|
34
|
+
"required": ["managingAgent"],
|
|
35
|
+
"properties": {
|
|
36
|
+
"managingAgent": {
|
|
37
|
+
"macRef": "MAC.4.1c",
|
|
38
|
+
"required": ["contact"],
|
|
39
|
+
"properties": {
|
|
40
|
+
"contact": {
|
|
41
|
+
"macRef": "MAC.4.1c",
|
|
42
|
+
"required": ["nameOrOrganisation"],
|
|
43
|
+
"properties": {
|
|
44
|
+
"nameOrOrganisation": {
|
|
45
|
+
"macRef": "MAC.4.1c.1"
|
|
46
|
+
},
|
|
47
|
+
"address": {
|
|
48
|
+
"macRef": "MAC.4.1c.0",
|
|
49
|
+
"properties": {
|
|
50
|
+
"line1": {
|
|
51
|
+
"macRef": "MAC.4.1c.2"
|
|
52
|
+
},
|
|
53
|
+
"line2": {
|
|
54
|
+
"macRef": "MAC.4.1c.3"
|
|
55
|
+
},
|
|
56
|
+
"line3": {
|
|
57
|
+
"macRef": "MAC.4.1c.4"
|
|
58
|
+
},
|
|
59
|
+
"town": {
|
|
60
|
+
"macRef": "MAC.4.1c.5"
|
|
61
|
+
},
|
|
62
|
+
"postcode": {
|
|
63
|
+
"macRef": "MAC.4.1c.6"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"telephone": {
|
|
68
|
+
"macRef": "MAC.4.1c.7"
|
|
69
|
+
},
|
|
70
|
+
"emailAddress": {
|
|
71
|
+
"macRef": "MAC.4.1c.8"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -985,7 +985,13 @@
|
|
|
985
985
|
"url": "https://example.com/example-agency-agreement",
|
|
986
986
|
"externalIds": {
|
|
987
987
|
"Moverly": "file123"
|
|
988
|
-
}
|
|
988
|
+
},
|
|
989
|
+
"requiredSignatories": [
|
|
990
|
+
{
|
|
991
|
+
"role": "Seller",
|
|
992
|
+
"requiresAll": true
|
|
993
|
+
}
|
|
994
|
+
]
|
|
989
995
|
},
|
|
990
996
|
"terms": {
|
|
991
997
|
"propertyAddress": "123 Maple Street, London, SW1A 1AA",
|
|
@@ -39328,12 +39328,38 @@
|
|
|
39328
39328
|
"properties": {
|
|
39329
39329
|
"template": {
|
|
39330
39330
|
"type": "object",
|
|
39331
|
-
"required": ["name", "url"],
|
|
39331
|
+
"required": ["name", "url", "requiredSignatories"],
|
|
39332
39332
|
"properties": {
|
|
39333
39333
|
"name": { "type": "string" },
|
|
39334
39334
|
"url": { "type": "string", "format": "uri" },
|
|
39335
39335
|
"externalIds": {
|
|
39336
39336
|
"type": "object"
|
|
39337
|
+
},
|
|
39338
|
+
"requiredSignatories": {
|
|
39339
|
+
"type": "array",
|
|
39340
|
+
"items": {
|
|
39341
|
+
"type": "object",
|
|
39342
|
+
"properties": {
|
|
39343
|
+
"role": {
|
|
39344
|
+
"type": "string",
|
|
39345
|
+
"enum": [
|
|
39346
|
+
"Seller",
|
|
39347
|
+
"Seller's Conveyancer",
|
|
39348
|
+
"Prospective Buyer",
|
|
39349
|
+
"Buyer",
|
|
39350
|
+
"Buyer's Conveyancer",
|
|
39351
|
+
"Estate Agent",
|
|
39352
|
+
"Buyer's Agent",
|
|
39353
|
+
"Surveyor",
|
|
39354
|
+
"Mortgage Broker",
|
|
39355
|
+
"Lender",
|
|
39356
|
+
"Landlord",
|
|
39357
|
+
"Tenant"
|
|
39358
|
+
]
|
|
39359
|
+
},
|
|
39360
|
+
"requiresAll": { "type": "boolean" }
|
|
39361
|
+
}
|
|
39362
|
+
}
|
|
39337
39363
|
}
|
|
39338
39364
|
}
|
|
39339
39365
|
},
|
|
@@ -34137,7 +34137,8 @@
|
|
|
34137
34137
|
"type": "object",
|
|
34138
34138
|
"required": [
|
|
34139
34139
|
"name",
|
|
34140
|
-
"url"
|
|
34140
|
+
"url",
|
|
34141
|
+
"requiredSignatories"
|
|
34141
34142
|
],
|
|
34142
34143
|
"properties": {
|
|
34143
34144
|
"name": {
|
|
@@ -34149,6 +34150,34 @@
|
|
|
34149
34150
|
},
|
|
34150
34151
|
"externalIds": {
|
|
34151
34152
|
"type": "object"
|
|
34153
|
+
},
|
|
34154
|
+
"requiredSignatories": {
|
|
34155
|
+
"type": "array",
|
|
34156
|
+
"items": {
|
|
34157
|
+
"type": "object",
|
|
34158
|
+
"properties": {
|
|
34159
|
+
"role": {
|
|
34160
|
+
"type": "string",
|
|
34161
|
+
"enum": [
|
|
34162
|
+
"Seller",
|
|
34163
|
+
"Seller's Conveyancer",
|
|
34164
|
+
"Prospective Buyer",
|
|
34165
|
+
"Buyer",
|
|
34166
|
+
"Buyer's Conveyancer",
|
|
34167
|
+
"Estate Agent",
|
|
34168
|
+
"Buyer's Agent",
|
|
34169
|
+
"Surveyor",
|
|
34170
|
+
"Mortgage Broker",
|
|
34171
|
+
"Lender",
|
|
34172
|
+
"Landlord",
|
|
34173
|
+
"Tenant"
|
|
34174
|
+
]
|
|
34175
|
+
},
|
|
34176
|
+
"requiresAll": {
|
|
34177
|
+
"type": "boolean"
|
|
34178
|
+
}
|
|
34179
|
+
}
|
|
34180
|
+
}
|
|
34152
34181
|
}
|
|
34153
34182
|
}
|
|
34154
34183
|
},
|
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
getValidator,
|
|
9
9
|
getSubschemaValidator,
|
|
10
10
|
getTitleAtPath,
|
|
11
|
+
overlaysMap,
|
|
11
12
|
} = require("../../../index.js");
|
|
12
13
|
|
|
13
14
|
const exampleTransaction = require("../../examples/v3/exampleTransaction.json");
|
|
@@ -403,3 +404,227 @@ test("validates a valid contract", () => {
|
|
|
403
404
|
const isValid = validator(data);
|
|
404
405
|
expect(isValid).toBe(true);
|
|
405
406
|
});
|
|
407
|
+
|
|
408
|
+
test("overlay as key and as object produce identical results", () => {
|
|
409
|
+
// Get the NTS overlay object directly from the overlays map
|
|
410
|
+
const ntsOverlayObject = { ...overlaysMap[schemaId]["nts2023"] };
|
|
411
|
+
// Remove the $id to prevent schema registration conflicts
|
|
412
|
+
ntsOverlayObject.$id =
|
|
413
|
+
"https://trust.propdata.org.uk/schemas/v3/overlays/nts2024.json";
|
|
414
|
+
|
|
415
|
+
// Get schema using the key
|
|
416
|
+
const schemaWithKey = getTransactionSchema(schemaId, ["nts2023"]);
|
|
417
|
+
|
|
418
|
+
// Get schema using the object
|
|
419
|
+
const schemaWithObject = getTransactionSchema(schemaId, [ntsOverlayObject]);
|
|
420
|
+
|
|
421
|
+
// Create copies without $id for comparison
|
|
422
|
+
const schemaWithKeyNoId = { ...schemaWithKey };
|
|
423
|
+
const schemaWithObjectNoId = { ...schemaWithObject };
|
|
424
|
+
delete schemaWithKeyNoId.$id;
|
|
425
|
+
delete schemaWithObjectNoId.$id;
|
|
426
|
+
|
|
427
|
+
// Deep compare the results (excluding $id)
|
|
428
|
+
expect(schemaWithObjectNoId).toEqual(schemaWithKeyNoId);
|
|
429
|
+
|
|
430
|
+
// Test that validation produces the same errors
|
|
431
|
+
const validatorWithKey = getValidator(schemaId, ["nts2023"]);
|
|
432
|
+
const validatorWithObject = getValidator(schemaId, [ntsOverlayObject]);
|
|
433
|
+
|
|
434
|
+
validatorWithKey(exampleTransaction);
|
|
435
|
+
validatorWithObject(exampleTransaction);
|
|
436
|
+
|
|
437
|
+
// Compare validation errors
|
|
438
|
+
expect(validatorWithObject.errors).toEqual(validatorWithKey.errors);
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
test("correctly merges custom Japanese Knotweed overlay with base schema", () => {
|
|
442
|
+
// Load the custom overlay
|
|
443
|
+
const customOverlay = require("../../examples/v3/exampleCustomOverlay.json");
|
|
444
|
+
|
|
445
|
+
// Get base schema and schema with overlay
|
|
446
|
+
const baseSchema = getTransactionSchema(schemaId);
|
|
447
|
+
const schemaWithOverlay = getTransactionSchema(schemaId, [customOverlay]);
|
|
448
|
+
|
|
449
|
+
// Verify that other properties in propertyPack are preserved
|
|
450
|
+
expect(
|
|
451
|
+
Object.keys(schemaWithOverlay.properties.propertyPack.properties)
|
|
452
|
+
).toEqual(Object.keys(baseSchema.properties.propertyPack.properties));
|
|
453
|
+
|
|
454
|
+
// Verify that other properties in specialistIssues are preserved
|
|
455
|
+
const baseSpecialistIssues =
|
|
456
|
+
baseSchema.properties.propertyPack.properties.specialistIssues;
|
|
457
|
+
const overlaidSpecialistIssues =
|
|
458
|
+
schemaWithOverlay.properties.propertyPack.properties.specialistIssues;
|
|
459
|
+
expect(Object.keys(overlaidSpecialistIssues.properties)).toEqual(
|
|
460
|
+
Object.keys(baseSpecialistIssues.properties)
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
// Verify that Japanese Knotweed section is updated
|
|
464
|
+
const japaneseKnotweed = overlaidSpecialistIssues.properties.japaneseKnotweed;
|
|
465
|
+
expect(japaneseKnotweed.title).toBe(
|
|
466
|
+
"Is the property affected by Japanese knotweed?"
|
|
467
|
+
);
|
|
468
|
+
expect(japaneseKnotweed.required).toEqual(["yesNo"]);
|
|
469
|
+
|
|
470
|
+
// Verify the oneOf conditions are updated
|
|
471
|
+
expect(japaneseKnotweed.oneOf).toHaveLength(2);
|
|
472
|
+
expect(japaneseKnotweed.oneOf[0].properties.yesNo.enum).toEqual([
|
|
473
|
+
"No",
|
|
474
|
+
"Not known",
|
|
475
|
+
]);
|
|
476
|
+
expect(japaneseKnotweed.oneOf[1].properties.yesNo.enum).toEqual(["Yes"]);
|
|
477
|
+
expect(japaneseKnotweed.oneOf[1].required).toEqual([
|
|
478
|
+
"managementPlanInPlace",
|
|
479
|
+
"attachments",
|
|
480
|
+
]);
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
test("correctly merges multiple overlays using both key and object references", () => {
|
|
484
|
+
// Load the custom overlay
|
|
485
|
+
const customOverlay = require("../../examples/v3/exampleCustomOverlay.json");
|
|
486
|
+
|
|
487
|
+
// Get schema with both overlays
|
|
488
|
+
const schemaWithOverlays = getTransactionSchema(schemaId, [
|
|
489
|
+
"nts2023",
|
|
490
|
+
customOverlay,
|
|
491
|
+
]);
|
|
492
|
+
|
|
493
|
+
// Get individual overlay schemas for comparison
|
|
494
|
+
const ntsSchema = getTransactionSchema(schemaId, ["nts2023"]);
|
|
495
|
+
const customSchema = getTransactionSchema(schemaId, [customOverlay]);
|
|
496
|
+
|
|
497
|
+
// Verify propertyPack structure is preserved
|
|
498
|
+
const propertyPack = schemaWithOverlays.properties.propertyPack;
|
|
499
|
+
expect(Object.keys(propertyPack.properties)).toEqual(
|
|
500
|
+
expect.arrayContaining(
|
|
501
|
+
Object.keys(ntsSchema.properties.propertyPack.properties)
|
|
502
|
+
)
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
// Verify Japanese Knotweed changes from custom overlay are present
|
|
506
|
+
const japaneseKnotweed =
|
|
507
|
+
propertyPack.properties.specialistIssues.properties.japaneseKnotweed;
|
|
508
|
+
expect(japaneseKnotweed.title).toBe(
|
|
509
|
+
"Is the property affected by Japanese knotweed?"
|
|
510
|
+
);
|
|
511
|
+
expect(japaneseKnotweed.oneOf[1].required).toEqual([
|
|
512
|
+
"managementPlanInPlace",
|
|
513
|
+
"attachments",
|
|
514
|
+
]);
|
|
515
|
+
|
|
516
|
+
// Verify customRef properties are correctly merged
|
|
517
|
+
expect(propertyPack.customRef).toBe("JKW");
|
|
518
|
+
expect(propertyPack.properties.specialistIssues.customRef).toBe("JKW.7");
|
|
519
|
+
expect(japaneseKnotweed.customRef).toBe("JKW.7.8");
|
|
520
|
+
expect(
|
|
521
|
+
japaneseKnotweed.oneOf[1].properties.managementPlanInPlace.customRef
|
|
522
|
+
).toBe("JKW.7.8.2");
|
|
523
|
+
expect(japaneseKnotweed.oneOf[1].properties.attachments.customRef).toBe(
|
|
524
|
+
"JKW.7.8.3"
|
|
525
|
+
);
|
|
526
|
+
expect(japaneseKnotweed.properties.yesNo.customRef).toBe("JKW.7.8.1");
|
|
527
|
+
|
|
528
|
+
// Verify NTS specific changes are present (e.g., simplified enums)
|
|
529
|
+
const mainsElectricity =
|
|
530
|
+
propertyPack.properties.electricity.properties.mainsElectricity;
|
|
531
|
+
expect(mainsElectricity.properties.yesNo.enum).toEqual(["Yes", "No"]);
|
|
532
|
+
|
|
533
|
+
// Verify required fields from both overlays are merged
|
|
534
|
+
expect(propertyPack.required).toEqual(
|
|
535
|
+
expect.arrayContaining([
|
|
536
|
+
...ntsSchema.properties.propertyPack.required,
|
|
537
|
+
...customSchema.properties.propertyPack.required,
|
|
538
|
+
])
|
|
539
|
+
);
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
test("correctly merges NTS and both custom overlays with proper required fields", () => {
|
|
543
|
+
// Load both custom overlays
|
|
544
|
+
const japaneseKnoweedOverlay = require("../../examples/v3/exampleCustomOverlay.json");
|
|
545
|
+
const managingAgentOverlay = require("../../examples/v3/exampleCustomOverlay2.json");
|
|
546
|
+
|
|
547
|
+
// Get schema with all overlays
|
|
548
|
+
const schemaWithOverlays = getTransactionSchema(schemaId, [
|
|
549
|
+
"nts2023",
|
|
550
|
+
japaneseKnoweedOverlay,
|
|
551
|
+
managingAgentOverlay,
|
|
552
|
+
]);
|
|
553
|
+
|
|
554
|
+
// Navigate to the leasehold section in the oneOf array
|
|
555
|
+
const leaseholdSchema =
|
|
556
|
+
schemaWithOverlays.properties.propertyPack.properties.ownership.properties.ownershipsToBeTransferred.items.oneOf.find(
|
|
557
|
+
(schema) => schema.properties.ownershipType.enum[0] === "Leasehold"
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
// Verify the leasehold information structure
|
|
561
|
+
const leaseholdInfo = leaseholdSchema.properties.leaseholdInformation;
|
|
562
|
+
|
|
563
|
+
// Check required fields - should include both NTS and custom overlay requirements
|
|
564
|
+
expect(leaseholdInfo.required).toContain("contactDetails");
|
|
565
|
+
expect(leaseholdInfo.required).toContain("leaseTerm"); // from NTS
|
|
566
|
+
expect(leaseholdInfo.required).toContain("groundRent"); // from NTS
|
|
567
|
+
|
|
568
|
+
// Verify managing agent contact structure and refs
|
|
569
|
+
const managingAgent =
|
|
570
|
+
leaseholdInfo.properties.contactDetails.properties.contacts.properties
|
|
571
|
+
.managingAgent;
|
|
572
|
+
expect(managingAgent.macRef).toBe("MAC.4.1c");
|
|
573
|
+
|
|
574
|
+
// Verify contact details structure
|
|
575
|
+
const contact = managingAgent.properties.contact;
|
|
576
|
+
expect(contact.properties.nameOrOrganisation.macRef).toBe("MAC.4.1c.1");
|
|
577
|
+
expect(contact.properties.address.macRef).toBe("MAC.4.1c.0");
|
|
578
|
+
expect(contact.properties.telephone.macRef).toBe("MAC.4.1c.7");
|
|
579
|
+
expect(contact.properties.emailAddress.macRef).toBe("MAC.4.1c.8");
|
|
580
|
+
|
|
581
|
+
// Verify Japanese Knotweed section is still present and correct
|
|
582
|
+
const japaneseKnotweed =
|
|
583
|
+
schemaWithOverlays.properties.propertyPack.properties.specialistIssues
|
|
584
|
+
.properties.japaneseKnotweed;
|
|
585
|
+
expect(japaneseKnotweed.customRef).toBe("JKW.7.8");
|
|
586
|
+
|
|
587
|
+
// Verify NTS changes are still present
|
|
588
|
+
const mainsElectricity =
|
|
589
|
+
schemaWithOverlays.properties.propertyPack.properties.electricity.properties
|
|
590
|
+
.mainsElectricity;
|
|
591
|
+
expect(mainsElectricity.properties.yesNo.enum).toEqual(["Yes", "No"]);
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
test("ta7 overlay as key and as object produce identical results at leasehold info level", () => {
|
|
595
|
+
// Get the TA7 overlay object directly from the overlays map
|
|
596
|
+
const ta7OverlayObject = { ...overlaysMap[schemaId]["ta7ed3"] };
|
|
597
|
+
// Remove the $id to prevent schema registration conflicts
|
|
598
|
+
ta7OverlayObject.$id =
|
|
599
|
+
"https://trust.propdata.org.uk/schemas/v3/overlays/ta7ed3-copy.json";
|
|
600
|
+
|
|
601
|
+
// Get schemas using both methods
|
|
602
|
+
const schemaWithKey = getTransactionSchema(schemaId, ["ta7ed3"]);
|
|
603
|
+
const schemaWithObject = getTransactionSchema(schemaId, [ta7OverlayObject]);
|
|
604
|
+
|
|
605
|
+
// Navigate to the leasehold information section in both schemas
|
|
606
|
+
const getLeaseholdInfo = (schema) => {
|
|
607
|
+
const ownershipsToBeTransferred =
|
|
608
|
+
schema.properties.propertyPack.properties.ownership.properties
|
|
609
|
+
.ownershipsToBeTransferred;
|
|
610
|
+
const leaseholdSchema = ownershipsToBeTransferred.items.oneOf.find(
|
|
611
|
+
(schema) => schema.properties.ownershipType.enum[0] === "Leasehold"
|
|
612
|
+
);
|
|
613
|
+
return leaseholdSchema.properties.leaseholdInformation;
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
const leaseholdInfoWithKey = getLeaseholdInfo(schemaWithKey);
|
|
617
|
+
const leaseholdInfoWithObject = getLeaseholdInfo(schemaWithObject);
|
|
618
|
+
|
|
619
|
+
// Deep compare the leasehold information sections
|
|
620
|
+
expect(leaseholdInfoWithObject).toEqual(leaseholdInfoWithKey);
|
|
621
|
+
|
|
622
|
+
// Verify specific TA7 requirements are present in both
|
|
623
|
+
expect(leaseholdInfoWithKey.required).toContain("contactDetails");
|
|
624
|
+
expect(leaseholdInfoWithObject.required).toContain("contactDetails");
|
|
625
|
+
|
|
626
|
+
// Verify TA7 refs are present and identical
|
|
627
|
+
const contactDetails = leaseholdInfoWithKey.properties.contactDetails;
|
|
628
|
+
expect(contactDetails.ta7Ref).toBe("4.1");
|
|
629
|
+
expect(leaseholdInfoWithObject.properties.contactDetails.ta7Ref).toBe("4.1");
|
|
630
|
+
});
|