@pdtf/schemas 2.3.0 → 3.0.0-2
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 +37 -81
- package/package.json +1 -1
- package/src/examples/v2/exampleTransaction.json +6 -20
- package/src/examples/v3/exampleTransaction.json +900 -0
- package/src/mappings/SendPropertyDetailsRequestSchema.json +1588 -0
- package/src/mappings/adf.js +1 -1
- package/src/schemas/v2/combined.json +13206 -12615
- package/src/schemas/v2/overlays/con29DW.json +771 -762
- package/src/schemas/v2/overlays/con29R.json +3052 -3073
- package/src/schemas/v2/overlays/llc1.json +12 -33
- package/src/schemas/v2/overlays/rds.json +32 -0
- package/src/schemas/v2/pdtf-transaction.json +13656 -12911
- package/src/schemas/v2/skeleton.json +1342 -1155
- package/src/schemas/v3/combined.json +38325 -0
- package/src/schemas/v3/overlays/baspi.json +9812 -0
- package/src/schemas/v3/overlays/con29DW.json +794 -0
- package/src/schemas/v3/overlays/con29R.json +3094 -0
- package/src/schemas/v3/overlays/fme1.json +1444 -0
- package/src/schemas/v3/overlays/llc1.json +25 -0
- package/src/schemas/v3/overlays/lpe1.json +2463 -0
- package/src/schemas/v3/overlays/nts.json +1884 -0
- package/src/schemas/v3/overlays/oc1.json +2799 -0
- package/src/schemas/v3/overlays/piq.json +3931 -0
- package/src/schemas/v3/overlays/rds.json +4086 -0
- package/src/schemas/v3/overlays/ta10.json +6521 -0
- package/src/schemas/v3/overlays/ta6.json +5285 -0
- package/src/schemas/v3/overlays/ta7.json +1399 -0
- package/src/schemas/v3/pdtf-transaction.json +34771 -0
- package/src/schemas/v3/skeleton.json +3986 -0
- package/src/tests/v2/transactionSchema.test.js +26 -16
- package/src/tests/v3/transactionSchema.test.js +350 -0
- package/src/tests/v3/verifiedClaimsValidator.test.js +128 -0
- package/src/utils/extractOverlay.js +7 -7
- package/src/utils/hmlrLLC1.json +0 -275
|
@@ -17,7 +17,7 @@ const schemaId =
|
|
|
17
17
|
const v2TransactionSchema = getTransactionSchema(schemaId);
|
|
18
18
|
|
|
19
19
|
test("exports a property pack schema, v2 with baspi overlay by default", () => {
|
|
20
|
-
const testSchema = getTransactionSchema();
|
|
20
|
+
const testSchema = getTransactionSchema(schemaId);
|
|
21
21
|
expect(testSchema.$id).toEqual(
|
|
22
22
|
"https://trust.propdata.org.uk/schemas/v2/pdtf-transaction.json"
|
|
23
23
|
);
|
|
@@ -27,10 +27,11 @@ test("exports a property pack schema, v2 with baspi overlay by default", () => {
|
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
test("sample is valid BASPI", () => {
|
|
30
|
-
const testSchema = getTransactionSchema();
|
|
30
|
+
const testSchema = getTransactionSchema(schemaId);
|
|
31
31
|
expect(
|
|
32
|
-
testSchema.properties.propertyPack.properties.materialFacts.
|
|
33
|
-
|
|
32
|
+
testSchema.properties.propertyPack.properties.materialFacts.properties
|
|
33
|
+
.centralHeating.title
|
|
34
|
+
).toEqual("Central Heating");
|
|
34
35
|
const validator = getValidator(schemaId);
|
|
35
36
|
const isValid = validator(exampleTransaction);
|
|
36
37
|
if (!isValid) console.log(validator.errors);
|
|
@@ -59,17 +60,17 @@ test("sample with missing dependent required fields is invalid", () => {
|
|
|
59
60
|
});
|
|
60
61
|
|
|
61
62
|
test("correctly gets a top level subschema", () => {
|
|
62
|
-
const subschema = getSubschema("/propertyPack");
|
|
63
|
+
const subschema = getSubschema("/propertyPack", schemaId);
|
|
63
64
|
expect(subschema.title).toBe("Property Pack");
|
|
64
65
|
});
|
|
65
66
|
|
|
66
67
|
test("correctly identifies a valid path", () => {
|
|
67
|
-
const isValid = isPathValid("/propertyPack/materialFacts");
|
|
68
|
+
const isValid = isPathValid("/propertyPack/materialFacts", schemaId);
|
|
68
69
|
expect(isValid).toBe(true);
|
|
69
70
|
});
|
|
70
71
|
|
|
71
72
|
test("correctly identifies an undefined invalid path", () => {
|
|
72
|
-
const isValid = isPathValid("/propertyPack/materialItems");
|
|
73
|
+
const isValid = isPathValid("/propertyPack/materialItems", schemaId);
|
|
73
74
|
expect(isValid).toBe(false);
|
|
74
75
|
});
|
|
75
76
|
|
|
@@ -82,7 +83,7 @@ test("correctly identifies an error generating invalid path", () => {
|
|
|
82
83
|
});
|
|
83
84
|
|
|
84
85
|
test("correctly identifies an array invalid path", () => {
|
|
85
|
-
const isValid = isPathValid("/propertyPack/materialFacts/1/item");
|
|
86
|
+
const isValid = isPathValid("/propertyPack/materialFacts/1/item", schemaId);
|
|
86
87
|
expect(isValid).toBe(false);
|
|
87
88
|
});
|
|
88
89
|
|
|
@@ -125,14 +126,16 @@ test("correctly gets another subschema through a dependency", () => {
|
|
|
125
126
|
|
|
126
127
|
test("correctly gets yet another subschema through a dependency", () => {
|
|
127
128
|
const subschema = getSubschema(
|
|
128
|
-
"/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/groundRent/rentSubjectToIncrease/rentIncreaseCalculated"
|
|
129
|
+
"/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/groundRent/rentSubjectToIncrease/rentIncreaseCalculated",
|
|
130
|
+
schemaId
|
|
129
131
|
);
|
|
130
132
|
expect(subschema.title).toBe("How is the increase calculated?");
|
|
131
133
|
});
|
|
132
134
|
|
|
133
135
|
test("correctly gets yet, yet another subschema through a dependency", () => {
|
|
134
136
|
const subschema = getSubschema(
|
|
135
|
-
"/propertyPack/materialFacts/listingAndConservation/isConservationArea/yesNo"
|
|
137
|
+
"/propertyPack/materialFacts/listingAndConservation/isConservationArea/yesNo",
|
|
138
|
+
schemaId
|
|
136
139
|
);
|
|
137
140
|
expect(subschema.type).toBe("string");
|
|
138
141
|
expect(subschema.enum).toStrictEqual(["Yes", "No", "Not known"]);
|
|
@@ -140,7 +143,8 @@ test("correctly gets yet, yet another subschema through a dependency", () => {
|
|
|
140
143
|
|
|
141
144
|
test("correctly gets yet, yet, yet another subschema through a dependency", () => {
|
|
142
145
|
const subschema = getSubschema(
|
|
143
|
-
"/propertyPack/materialFacts/environmentalIssues/flooding/typeOfFlooding/other/yesNo"
|
|
146
|
+
"/propertyPack/materialFacts/environmentalIssues/flooding/typeOfFlooding/other/yesNo",
|
|
147
|
+
schemaId
|
|
144
148
|
);
|
|
145
149
|
expect(subschema.type).toBe("string");
|
|
146
150
|
expect(subschema.enum).toStrictEqual(["Yes", "No"]);
|
|
@@ -148,21 +152,24 @@ test("correctly gets yet, yet, yet another subschema through a dependency", () =
|
|
|
148
152
|
|
|
149
153
|
test("correctly gets yet, yet, yet another subschema through a second item dependency", () => {
|
|
150
154
|
const subschema = getSubschema(
|
|
151
|
-
"/propertyPack/materialFacts/environmentalIssues/flooding/typeOfFlooding"
|
|
155
|
+
"/propertyPack/materialFacts/environmentalIssues/flooding/typeOfFlooding",
|
|
156
|
+
schemaId
|
|
152
157
|
);
|
|
153
158
|
expect(subschema.type).toBe("object");
|
|
154
159
|
});
|
|
155
160
|
|
|
156
161
|
test("correctly gets yes another subschema but through a non-baspi oneOf structure", () => {
|
|
157
162
|
const subschema = getSubschema(
|
|
158
|
-
"/propertyPack/titlesToBeSold/0/registerExtract/OCSummaryData/RestrictionDetails/RestrictionEntry/ChargeRestriction/EntryDetails/EntryText"
|
|
163
|
+
"/propertyPack/titlesToBeSold/0/registerExtract/OCSummaryData/RestrictionDetails/RestrictionEntry/ChargeRestriction/EntryDetails/EntryText",
|
|
164
|
+
schemaId
|
|
159
165
|
);
|
|
160
166
|
expect(subschema).toEqual({ type: "string" });
|
|
161
167
|
});
|
|
162
168
|
|
|
163
169
|
test("correctly gets yes another subschema but through a non-baspi oneOf structure with array option", () => {
|
|
164
170
|
const subschema = getSubschema(
|
|
165
|
-
"/propertyPack/titlesToBeSold/0/registerExtract/OCSummaryData/RestrictionDetails/RestrictionEntry/0/ChargeRestriction/EntryDetails/EntryText"
|
|
171
|
+
"/propertyPack/titlesToBeSold/0/registerExtract/OCSummaryData/RestrictionDetails/RestrictionEntry/0/ChargeRestriction/EntryDetails/EntryText",
|
|
172
|
+
schemaId
|
|
166
173
|
);
|
|
167
174
|
expect(subschema).toEqual({ type: "string" });
|
|
168
175
|
});
|
|
@@ -179,11 +186,13 @@ test("correctly gets a subschema with multiple overlays", () => {
|
|
|
179
186
|
|
|
180
187
|
test("correctly gets a subschema validator which is already cached", () => {
|
|
181
188
|
const validator = getSubschemaValidator(
|
|
182
|
-
"/propertyPack/materialFacts/energyEfficiency/certificate"
|
|
189
|
+
"/propertyPack/materialFacts/energyEfficiency/certificate",
|
|
190
|
+
schemaId
|
|
183
191
|
);
|
|
184
192
|
expect(validator).not.toBeNull();
|
|
185
193
|
const anotherValidator = getSubschemaValidator(
|
|
186
|
-
"/propertyPack/materialFacts/energyEfficiency/certificate"
|
|
194
|
+
"/propertyPack/materialFacts/energyEfficiency/certificate",
|
|
195
|
+
schemaId
|
|
187
196
|
);
|
|
188
197
|
expect(anotherValidator).not.toBeNull();
|
|
189
198
|
});
|
|
@@ -238,6 +247,7 @@ test("correctly gets a subschema validator for a TA6 overlay which validates wit
|
|
|
238
247
|
"ta6ed4",
|
|
239
248
|
]);
|
|
240
249
|
let isValid = validator(data);
|
|
250
|
+
// console.log(validator.errors);
|
|
241
251
|
expect(isValid).toBe(true);
|
|
242
252
|
});
|
|
243
253
|
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
const jp = require("jsonpointer");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
getTransactionSchema,
|
|
6
|
+
getSubschema,
|
|
7
|
+
isPathValid,
|
|
8
|
+
getValidator,
|
|
9
|
+
getSubschemaValidator,
|
|
10
|
+
getTitleAtPath,
|
|
11
|
+
} = require("../../../index.js");
|
|
12
|
+
|
|
13
|
+
const exampleTransaction = require("../../examples/v3/exampleTransaction.json");
|
|
14
|
+
const schemaId =
|
|
15
|
+
"https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json";
|
|
16
|
+
// const validator = getValidator(schemaId);
|
|
17
|
+
const v3TransactionSchema = getTransactionSchema(schemaId);
|
|
18
|
+
|
|
19
|
+
test("exports a property pack schema, v3 with baspi overlay by default", () => {
|
|
20
|
+
const testSchema = getTransactionSchema();
|
|
21
|
+
expect(testSchema.$id).toEqual(
|
|
22
|
+
"https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json"
|
|
23
|
+
);
|
|
24
|
+
expect(
|
|
25
|
+
testSchema.properties.propertyPack.properties.materialFacts.baspiRef
|
|
26
|
+
).toEqual("A");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("sample is valid BASPI", () => {
|
|
30
|
+
const testSchema = getTransactionSchema();
|
|
31
|
+
expect(
|
|
32
|
+
testSchema.properties.propertyPack.properties.materialFacts.baspiRef
|
|
33
|
+
).toEqual("A");
|
|
34
|
+
const validator = getValidator(schemaId);
|
|
35
|
+
const isValid = validator(exampleTransaction);
|
|
36
|
+
if (!isValid) console.log(validator.errors);
|
|
37
|
+
expect(isValid).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("sample is valid NTS", () => {
|
|
41
|
+
const validator = getValidator(schemaId, ["nts2023"]);
|
|
42
|
+
const isValid = validator(exampleTransaction);
|
|
43
|
+
if (!isValid) console.log(validator.errors);
|
|
44
|
+
expect(isValid).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("invalid sample is invalid", () => {
|
|
48
|
+
const clonedExampleTransaction = JSON.parse(
|
|
49
|
+
JSON.stringify(exampleTransaction)
|
|
50
|
+
);
|
|
51
|
+
delete clonedExampleTransaction.propertyPack.materialFacts.notices;
|
|
52
|
+
const validator = getValidator(schemaId);
|
|
53
|
+
const isValid = validator(clonedExampleTransaction);
|
|
54
|
+
expect(isValid).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("sample with missing dependent required fields is invalid", () => {
|
|
58
|
+
const clonedExampleTransaction = JSON.parse(
|
|
59
|
+
JSON.stringify(exampleTransaction)
|
|
60
|
+
);
|
|
61
|
+
clonedExampleTransaction.propertyPack.materialFacts.ownership.ownershipsToBeTransferred[0].ownershipType =
|
|
62
|
+
"leasehold";
|
|
63
|
+
const validator = getValidator(schemaId);
|
|
64
|
+
const isValid = validator(clonedExampleTransaction);
|
|
65
|
+
expect(isValid).toBe(false);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("correctly gets a top level subschema", () => {
|
|
69
|
+
const subschema = getSubschema("/propertyPack");
|
|
70
|
+
expect(subschema.title).toBe("Property Pack");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("correctly identifies a valid path", () => {
|
|
74
|
+
const isValid = isPathValid("/propertyPack/materialFacts");
|
|
75
|
+
expect(isValid).toBe(true);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("correctly identifies an undefined invalid path", () => {
|
|
79
|
+
const isValid = isPathValid("/propertyPack/materialItems");
|
|
80
|
+
expect(isValid).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("correctly identifies an error generating invalid path", () => {
|
|
84
|
+
const isValid = isPathValid(
|
|
85
|
+
"/propertyPack/materialItems/someProperty/item",
|
|
86
|
+
schemaId
|
|
87
|
+
);
|
|
88
|
+
expect(isValid).toBe(false);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("correctly identifies an array invalid path", () => {
|
|
92
|
+
const isValid = isPathValid("/propertyPack/materialFacts/1/item");
|
|
93
|
+
expect(isValid).toBe(false);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("correctly gets a subschema", () => {
|
|
97
|
+
const subschema = getSubschema(
|
|
98
|
+
"/propertyPack/materialFacts/notices",
|
|
99
|
+
schemaId
|
|
100
|
+
);
|
|
101
|
+
expect(subschema.title).toBe("Notices which Affect the Property");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("correctly gets a subschema through an arrays element", () => {
|
|
105
|
+
const subschema = getSubschema(
|
|
106
|
+
"/propertyPack/titlesToBeSold/0/registerExtract",
|
|
107
|
+
schemaId
|
|
108
|
+
);
|
|
109
|
+
expect(Object.keys(subschema.properties)).toEqual([
|
|
110
|
+
"OCSummaryData",
|
|
111
|
+
"OCRegisterData",
|
|
112
|
+
]);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("correctly gets a subschema through a dependency", () => {
|
|
116
|
+
const subschema = getSubschema(
|
|
117
|
+
"/propertyPack/materialFacts/delayFactors/hasDelayFactors/details",
|
|
118
|
+
schemaId
|
|
119
|
+
);
|
|
120
|
+
expect(subschema.title).toBe(
|
|
121
|
+
"Provide details and likely timescale for delay"
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("correctly gets another subschema through a dependency", () => {
|
|
126
|
+
const subschema = getSubschema(
|
|
127
|
+
"/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/leaseTerm/lengthOfLeaseInYears",
|
|
128
|
+
schemaId
|
|
129
|
+
);
|
|
130
|
+
expect(subschema.title).toBe("Length of lease (years)");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("correctly gets yet another subschema through a dependency", () => {
|
|
134
|
+
const subschema = getSubschema(
|
|
135
|
+
"/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/groundRent/rentSubjectToIncrease/rentIncreaseCalculated"
|
|
136
|
+
);
|
|
137
|
+
expect(subschema.title).toBe("How is the increase calculated?");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("correctly gets yet, yet another subschema through a dependency", () => {
|
|
141
|
+
const subschema = getSubschema(
|
|
142
|
+
"/propertyPack/materialFacts/listingAndConservation/isConservationArea/yesNo"
|
|
143
|
+
);
|
|
144
|
+
expect(subschema.type).toBe("string");
|
|
145
|
+
expect(subschema.enum).toStrictEqual(["Yes", "No", "Not known"]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("correctly gets yet, yet, yet another subschema through a second item dependency", () => {
|
|
149
|
+
const subschema = getSubschema(
|
|
150
|
+
"/propertyPack/materialFacts/environmentalIssues/flooding/typeOfFlooding"
|
|
151
|
+
);
|
|
152
|
+
expect(subschema.type).toBe("array");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("correctly gets yes another subschema but through a non-baspi oneOf structure", () => {
|
|
156
|
+
const subschema = getSubschema(
|
|
157
|
+
"/propertyPack/titlesToBeSold/0/registerExtract/OCSummaryData/RestrictionDetails/RestrictionEntry/ChargeRestriction/EntryDetails/EntryText"
|
|
158
|
+
);
|
|
159
|
+
expect(subschema).toEqual({ type: "string" });
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("correctly gets yes another subschema but through a non-baspi oneOf structure with array option", () => {
|
|
163
|
+
const subschema = getSubschema(
|
|
164
|
+
"/propertyPack/titlesToBeSold/0/registerExtract/OCSummaryData/RestrictionDetails/RestrictionEntry/0/ChargeRestriction/EntryDetails/EntryText"
|
|
165
|
+
);
|
|
166
|
+
expect(subschema).toEqual({ type: "string" });
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("correctly gets a subschema with multiple overlays", () => {
|
|
170
|
+
const subschema = getSubschema(
|
|
171
|
+
"/propertyPack/materialFacts/parking/parkingArrangements",
|
|
172
|
+
schemaId,
|
|
173
|
+
["baspiV4", "ta6ed4"]
|
|
174
|
+
);
|
|
175
|
+
expect(subschema.baspiRef).toBe("A1.6.0");
|
|
176
|
+
expect(subschema.ta6Ref).toBe("9.1");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("correctly gets a subschema validator which is already cached", () => {
|
|
180
|
+
const validator = getSubschemaValidator(
|
|
181
|
+
"/propertyPack/materialFacts/energyEfficiency/certificate"
|
|
182
|
+
);
|
|
183
|
+
expect(validator).not.toBeNull();
|
|
184
|
+
const anotherValidator = getSubschemaValidator(
|
|
185
|
+
"/propertyPack/materialFacts/energyEfficiency/certificate"
|
|
186
|
+
);
|
|
187
|
+
expect(anotherValidator).not.toBeNull();
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test("correctly gets a subschema validator for a TA6 overlay", () => {
|
|
191
|
+
const path = "/propertyPack";
|
|
192
|
+
const data = jp.get(exampleTransaction, path);
|
|
193
|
+
const validator = getSubschemaValidator(path, exampleTransaction.$schema, [
|
|
194
|
+
"ta6ed4",
|
|
195
|
+
]);
|
|
196
|
+
let isValid = validator(data);
|
|
197
|
+
// console.log(validator.errors);
|
|
198
|
+
expect(isValid).toBe(true);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test("correctly gets a subschema validator for a TA6 overlay which validates", () => {
|
|
202
|
+
const path =
|
|
203
|
+
"/propertyPack/additionalLegalInfo/guaranteesWarrantiesAndIndemnityInsurances/subsidenceWork";
|
|
204
|
+
const data = { yesNo: "Yes" };
|
|
205
|
+
const validator = getSubschemaValidator(path, exampleTransaction.$schema, [
|
|
206
|
+
"ta6ed4",
|
|
207
|
+
]);
|
|
208
|
+
let isValid = validator(data);
|
|
209
|
+
expect(isValid).toBe(false);
|
|
210
|
+
expect(validator.errors[0].message).toBe(
|
|
211
|
+
"must have required property 'attachments'"
|
|
212
|
+
);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test("correctly gets a subschema validator for a TA6 overlay which validates with non-TA6 field missing", () => {
|
|
216
|
+
const path = "/propertyPack";
|
|
217
|
+
const clonedExampleTransaction = JSON.parse(
|
|
218
|
+
JSON.stringify(exampleTransaction)
|
|
219
|
+
);
|
|
220
|
+
const data = jp.get(exampleTransaction, path);
|
|
221
|
+
data.materialFacts.uprn = undefined;
|
|
222
|
+
const validator = getSubschemaValidator(path, exampleTransaction.$schema, [
|
|
223
|
+
"ta6ed4",
|
|
224
|
+
]);
|
|
225
|
+
let isValid = validator(data);
|
|
226
|
+
expect(isValid).toBe(true);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test("correctly gets a subschema validator for a TA6 overlay which validates with non-TA6 section missing", () => {
|
|
230
|
+
const path = "/propertyPack";
|
|
231
|
+
const clonedExampleTransaction = JSON.parse(
|
|
232
|
+
JSON.stringify(exampleTransaction)
|
|
233
|
+
);
|
|
234
|
+
const data = jp.get(clonedExampleTransaction, path);
|
|
235
|
+
data.additionalLegalInfo.smartHomeSystems = undefined;
|
|
236
|
+
const validator = getSubschemaValidator(path, exampleTransaction.$schema, [
|
|
237
|
+
"ta6ed4",
|
|
238
|
+
]);
|
|
239
|
+
let isValid = validator(data);
|
|
240
|
+
expect(isValid).toBe(true);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("correctly gets a subschema validator for a TA6 overlay which fails to validate with BASPI/TA6 section missing", () => {
|
|
244
|
+
const path = "/propertyPack";
|
|
245
|
+
const clonedExampleTransaction = JSON.parse(
|
|
246
|
+
JSON.stringify(exampleTransaction)
|
|
247
|
+
);
|
|
248
|
+
const data = jp.get(clonedExampleTransaction, path);
|
|
249
|
+
data.materialFacts.waterAndDrainage = {};
|
|
250
|
+
const validator = getSubschemaValidator(path, exampleTransaction.$schema, [
|
|
251
|
+
"ta6ed4",
|
|
252
|
+
]);
|
|
253
|
+
let isValid = validator(data);
|
|
254
|
+
expect(isValid).toBe(false);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test("correctly gets a subschema validator for an NTS overlay", () => {
|
|
258
|
+
const path = "/propertyPack";
|
|
259
|
+
const clonedExampleTransaction = JSON.parse(
|
|
260
|
+
JSON.stringify(exampleTransaction)
|
|
261
|
+
);
|
|
262
|
+
const data = jp.get(clonedExampleTransaction, path);
|
|
263
|
+
const validator = getSubschemaValidator(path, exampleTransaction.$schema, [
|
|
264
|
+
"nts2023",
|
|
265
|
+
]);
|
|
266
|
+
let isValid = validator(data);
|
|
267
|
+
expect(isValid).toBe(true);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test("correctly gets a subschema validator for an LPE1 overlay", () => {
|
|
271
|
+
const path = "/propertyPack";
|
|
272
|
+
const clonedExampleTransaction = JSON.parse(
|
|
273
|
+
JSON.stringify(exampleTransaction)
|
|
274
|
+
);
|
|
275
|
+
const data = jp.get(clonedExampleTransaction, path);
|
|
276
|
+
const validator = getSubschemaValidator(path, exampleTransaction.$schema, [
|
|
277
|
+
"lpe1ed4",
|
|
278
|
+
]);
|
|
279
|
+
let isValid = validator(data);
|
|
280
|
+
expect(isValid).toBe(false);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
test("correctly gets a subschema validator which validates", () => {
|
|
284
|
+
const path = "/propertyPack/materialFacts/notices";
|
|
285
|
+
const validator = getSubschemaValidator(path);
|
|
286
|
+
const data = jp.get(exampleTransaction, path);
|
|
287
|
+
expect(data.neighbourDevelopment.yesNo).toBe("No");
|
|
288
|
+
let isValid = validator(data);
|
|
289
|
+
expect(isValid).toBe(true);
|
|
290
|
+
data.neighbourDevelopment.yesNo = "Invalid string";
|
|
291
|
+
isValid = validator(data);
|
|
292
|
+
expect(isValid).toBe(false);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test("correctly gets titles across schemas, arrays and non-existient title properties", () => {
|
|
296
|
+
expect(
|
|
297
|
+
getTitleAtPath(
|
|
298
|
+
v3TransactionSchema,
|
|
299
|
+
"/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/ownershipType"
|
|
300
|
+
)
|
|
301
|
+
).toBe("What type of ownership is the property?");
|
|
302
|
+
expect(
|
|
303
|
+
getTitleAtPath(
|
|
304
|
+
v3TransactionSchema,
|
|
305
|
+
"/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/leaseTerm/lengthOfLeaseInYears"
|
|
306
|
+
)
|
|
307
|
+
).toBe("Length of lease (years)");
|
|
308
|
+
expect(
|
|
309
|
+
getTitleAtPath(
|
|
310
|
+
v3TransactionSchema,
|
|
311
|
+
"/propertyPack/materialFacts/ownership/ownershipsToBeTransferred/0/leaseholdInformation/serviceCharge/annualServiceCharge"
|
|
312
|
+
)
|
|
313
|
+
).toBe("Amount of current annual service charge (£)");
|
|
314
|
+
expect(
|
|
315
|
+
getTitleAtPath(
|
|
316
|
+
v3TransactionSchema,
|
|
317
|
+
"/propertyPack/materialFacts/invalidPath"
|
|
318
|
+
)
|
|
319
|
+
).toBe(undefined);
|
|
320
|
+
expect(
|
|
321
|
+
getTitleAtPath(
|
|
322
|
+
v3TransactionSchema,
|
|
323
|
+
"/propertyPack/titlesToBeSold/0/registerExtract"
|
|
324
|
+
)
|
|
325
|
+
).toBe("HMLR Official Copy Register Extract");
|
|
326
|
+
expect(
|
|
327
|
+
getTitleAtPath(
|
|
328
|
+
v3TransactionSchema,
|
|
329
|
+
"/propertyPack/titlesToBeSold/0/registerExtract/OCSummaryData/PropertyAddress"
|
|
330
|
+
)
|
|
331
|
+
).toBe("Property address");
|
|
332
|
+
expect(
|
|
333
|
+
getTitleAtPath(
|
|
334
|
+
v3TransactionSchema,
|
|
335
|
+
"/propertyPack/titlesToBeSold/0/registerExtract/OCSummaryData/InvalidProp"
|
|
336
|
+
)
|
|
337
|
+
).toBe(undefined);
|
|
338
|
+
expect(
|
|
339
|
+
getTitleAtPath(
|
|
340
|
+
v3TransactionSchema,
|
|
341
|
+
"/propertyPack/materialFacts/energyEfficiency/certificate/currentEnergyRating"
|
|
342
|
+
)
|
|
343
|
+
).toBe("Current energy efficiency rating");
|
|
344
|
+
expect(
|
|
345
|
+
getTitleAtPath(
|
|
346
|
+
v3TransactionSchema,
|
|
347
|
+
"/propertyPack/additionalLegalInfo/occupiers/othersAged17OrOver/aged17OrOverNames"
|
|
348
|
+
)
|
|
349
|
+
).toBe("Please provide their full names and ages.");
|
|
350
|
+
});
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const { validateVerifiedClaims } = require("../../../index.js");
|
|
2
|
+
|
|
3
|
+
const exampleVouch = require("../../examples/v1/exampleVouch.json");
|
|
4
|
+
const exampleDocumentedVouch = require("../../examples/v1/exampleDocumentedVouch.json");
|
|
5
|
+
const v3SchemaId =
|
|
6
|
+
"https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json";
|
|
7
|
+
|
|
8
|
+
test("returns an empty array for a valid claim", () => {
|
|
9
|
+
expect(validateVerifiedClaims([exampleVouch])).toEqual([]);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("returns an empty array for a valid array of claims", () => {
|
|
13
|
+
const claimsArray = [exampleVouch, exampleDocumentedVouch];
|
|
14
|
+
expect(validateVerifiedClaims(claimsArray)).toEqual([]);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("returns an array with an error stating if path is incorrect", () => {
|
|
18
|
+
const clonedVouch = JSON.parse(JSON.stringify(exampleVouch));
|
|
19
|
+
const originalPath = Object.keys(clonedVouch.claims)[0];
|
|
20
|
+
const data = clonedVouch.claims[originalPath];
|
|
21
|
+
clonedVouch.claims = {
|
|
22
|
+
"/propertyPack/INVALID/materialFacts/councilTax": data,
|
|
23
|
+
};
|
|
24
|
+
// v3 schema, no overlay
|
|
25
|
+
expect(validateVerifiedClaims([clonedVouch], v3SchemaId, null)).toEqual([
|
|
26
|
+
"Path /propertyPack/INVALID/materialFacts/councilTax is not a valid PDTF schema path",
|
|
27
|
+
]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("returns errors if BASPI requirements are not met and BASPI overlay is specified (default)", () => {
|
|
31
|
+
const clonedVouch = JSON.parse(JSON.stringify(exampleVouch));
|
|
32
|
+
clonedVouch.claims = {
|
|
33
|
+
"/propertyPack/materialFacts/delayFactors": {
|
|
34
|
+
hasDelayFactors: { yesNo: "Yes" },
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
const errors = validateVerifiedClaims([clonedVouch], v3SchemaId);
|
|
38
|
+
expect(errors).toEqual([
|
|
39
|
+
{
|
|
40
|
+
instancePath: "/hasDelayFactors",
|
|
41
|
+
schemaPath: "#/properties/hasDelayFactors/oneOf/1/required",
|
|
42
|
+
keyword: "required",
|
|
43
|
+
params: { missingProperty: "details" },
|
|
44
|
+
message: "must have required property 'details'",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
instancePath: "/hasDelayFactors",
|
|
48
|
+
schemaPath: "#/properties/hasDelayFactors/oneOf/1/required",
|
|
49
|
+
keyword: "required",
|
|
50
|
+
params: { missingProperty: "attachments" },
|
|
51
|
+
message: "must have required property 'attachments'",
|
|
52
|
+
},
|
|
53
|
+
]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("returns no errors if BASPI requirements are not met and null overlay is specified", () => {
|
|
57
|
+
const clonedVouch = JSON.parse(JSON.stringify(exampleVouch));
|
|
58
|
+
clonedVouch.claims = {
|
|
59
|
+
"/propertyPack/materialFacts/delayFactors": {
|
|
60
|
+
hasDelayFactors: { yesNo: "Yes" },
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
const errors = validateVerifiedClaims([clonedVouch], v3SchemaId, null);
|
|
64
|
+
expect(errors).toEqual([]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("returns errors for invalid fields even if null overlay is specified", () => {
|
|
68
|
+
const clonedVouch = JSON.parse(JSON.stringify(exampleVouch));
|
|
69
|
+
clonedVouch.claims = {
|
|
70
|
+
"/propertyPack/materialFacts/delayFactors": {
|
|
71
|
+
hasDelayFactors: { yesNo: "Maybe" },
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
const errors = validateVerifiedClaims([clonedVouch], v3SchemaId, null);
|
|
75
|
+
expect(errors).toHaveLength(4);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("returns an array of errors for verified claim with multiple paths", () => {
|
|
79
|
+
const clonedVouch = JSON.parse(JSON.stringify(exampleVouch));
|
|
80
|
+
clonedVouch.claims = {
|
|
81
|
+
"/propertyPack/materialFacts/cousncilTaxBad": {
|
|
82
|
+
councilTaxBand: "D",
|
|
83
|
+
councilTaxAffectingAlterations: {
|
|
84
|
+
yesNo: "Yes",
|
|
85
|
+
details:
|
|
86
|
+
"Extension added in 2005 to add bedroom with ensuite shower room. Certificate of Compliance issued 17th Feb 2006 and council tax updated",
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
"/propertyPack/materialFacts/councilTaxBadTwo": {
|
|
90
|
+
councilTaxBand: "D",
|
|
91
|
+
councilTaxAffectingAlterations: {
|
|
92
|
+
yesNo: "Yes",
|
|
93
|
+
details:
|
|
94
|
+
"Extension added in 2005 to add bedroom with ensuite shower room. Certificate of Compliance issued 17th Feb 2006 and council tax updated",
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
expect(validateVerifiedClaims([clonedVouch], v3SchemaId, null)).toEqual([
|
|
99
|
+
"Path /propertyPack/materialFacts/cousncilTaxBad is not a valid PDTF schema path",
|
|
100
|
+
"Path /propertyPack/materialFacts/councilTaxBadTwo is not a valid PDTF schema path",
|
|
101
|
+
]);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("returns an empty array of errors for verified claim with multiple valid paths", () => {
|
|
105
|
+
const clonedVouch = JSON.parse(
|
|
106
|
+
JSON.stringify(exampleVouch),
|
|
107
|
+
v3SchemaId,
|
|
108
|
+
null
|
|
109
|
+
);
|
|
110
|
+
clonedVouch.claims = {
|
|
111
|
+
"/propertyPack/materialFacts/councilTax": {
|
|
112
|
+
councilTaxBand: "D",
|
|
113
|
+
councilTaxAffectingAlterations: {
|
|
114
|
+
yesNo: "Yes",
|
|
115
|
+
details:
|
|
116
|
+
"Extension added in 2005 to add bedroom with ensuite shower room. Certificate of Compliance issued 17th Feb 2006 and council tax updated",
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
"/propertyPack/materialFacts/address": {
|
|
120
|
+
line1: "property.line1",
|
|
121
|
+
line2: "property.line2",
|
|
122
|
+
town: "property.city",
|
|
123
|
+
county: "property.province",
|
|
124
|
+
postcode: "property.postcode",
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
expect(validateVerifiedClaims([clonedVouch], v3SchemaId, null)).toEqual([]);
|
|
128
|
+
});
|
|
@@ -4,7 +4,7 @@ const jp = require("jsonpointer");
|
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const merge = require("deepmerge");
|
|
6
6
|
|
|
7
|
-
const combinedSchema = require("../schemas/
|
|
7
|
+
const combinedSchema = require("../schemas/v3/combined.json");
|
|
8
8
|
|
|
9
9
|
const extractFields = [
|
|
10
10
|
"baspi",
|
|
@@ -74,7 +74,7 @@ const extractOverlay = (sourceSchema, ref) => {
|
|
|
74
74
|
const refName = `${ref}Ref`;
|
|
75
75
|
const returnSchema = {
|
|
76
76
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
77
|
-
$id: `https://trust.propdata.org.uk/schemas/
|
|
77
|
+
$id: `https://trust.propdata.org.uk/schemas/v3/overlays/${ref}.json`,
|
|
78
78
|
};
|
|
79
79
|
traverse(sourceSchema).forEach(function (element) {
|
|
80
80
|
let path = "/" + this.path.join("/");
|
|
@@ -160,7 +160,7 @@ extractFields.forEach((key) => {
|
|
|
160
160
|
"discriminator",
|
|
161
161
|
]);
|
|
162
162
|
overlays[key] = overlay;
|
|
163
|
-
const fileName = `../schemas/
|
|
163
|
+
const fileName = `../schemas/v3/overlays/${key}.json`;
|
|
164
164
|
fs.writeFileSync(fileName, JSON.stringify(overlay, null, 2));
|
|
165
165
|
console.log(`Overlay ${key} written to ${fileName}`);
|
|
166
166
|
});
|
|
@@ -174,10 +174,10 @@ const coreSchema = deleteProperties(combinedSchema, [
|
|
|
174
174
|
]);
|
|
175
175
|
|
|
176
176
|
fs.writeFileSync(
|
|
177
|
-
"../schemas/
|
|
177
|
+
"../schemas/v3/pdtf-transaction.json",
|
|
178
178
|
JSON.stringify(coreSchema, null, 2)
|
|
179
179
|
);
|
|
180
|
-
console.log("Core schema written to ../schemas/
|
|
180
|
+
console.log("Core schema written to ../schemas/v3/pdtf-transaction.json");
|
|
181
181
|
|
|
182
182
|
const skeletonSchema = deleteProperties(coreSchema, [
|
|
183
183
|
"$schema",
|
|
@@ -196,7 +196,7 @@ const skeletonSchema = deleteProperties(coreSchema, [
|
|
|
196
196
|
const skeletonSchemaFlattened = flattenSkeleton(skeletonSchema);
|
|
197
197
|
|
|
198
198
|
fs.writeFileSync(
|
|
199
|
-
"../schemas/
|
|
199
|
+
"../schemas/v3/skeleton.json",
|
|
200
200
|
JSON.stringify(skeletonSchemaFlattened, null, 2)
|
|
201
201
|
);
|
|
202
|
-
console.log("Flat Skeleton schema written to ../schemas/
|
|
202
|
+
console.log("Flat Skeleton schema written to ../schemas/v3/skeleton.json");
|