@planning-inspectorate/data-model 1.16.0 → 1.17.0

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.
@@ -0,0 +1,227 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import Ajv from 'ajv';
4
+ import addFormats from 'ajv-formats';
5
+ import { loadAllSchemasSync } from '../../src/index.js';
6
+
7
+ const schema = 'appeal-s78.schema.json';
8
+
9
+ const appealS78 = {
10
+ caseId: 96989394,
11
+ caseReference: 'exercitation dolore',
12
+ submissionId: null,
13
+ caseStatus: 'transferred',
14
+ caseType: 'D',
15
+ caseProcedure: 'inquiry',
16
+ lpaCode: 'pariatur cillum non',
17
+ caseOfficerId: null,
18
+ inspectorId: 'amet magna dolor in labore',
19
+ allocationLevel: null,
20
+ allocationBand: null,
21
+ caseSpecialisms: ['laboris est proident minim', 'qui sunt ut', 'consectetur Lorem do sunt aliquip'],
22
+ caseSubmittedDate: '1907-08-17T13:18:33.0Z',
23
+ caseCreatedDate: '1906-08-08T04:49:02.0Z',
24
+ caseUpdatedDate: '1945-02-11T12:49:58.0Z',
25
+ caseValidDate: null,
26
+ caseValidationDate: null,
27
+ caseValidationOutcome: 'invalid',
28
+ caseValidationInvalidDetails: null,
29
+ caseValidationIncompleteDetails: null,
30
+ caseExtensionDate: null,
31
+ caseStartedDate: '1905-07-12T15:31:22.0Z',
32
+ casePublishedDate: null,
33
+ linkedCaseStatus: 'lead',
34
+ leadCaseReference: null,
35
+ lpaQuestionnaireDueDate: null,
36
+ lpaQuestionnaireSubmittedDate: null,
37
+ lpaQuestionnaireCreatedDate: '1956-11-08T15:53:10.0Z',
38
+ lpaQuestionnairePublishedDate: '1951-09-03T07:25:19.0Z',
39
+ lpaQuestionnaireValidationOutcome: null,
40
+ lpaQuestionnaireValidationOutcomeDate: null,
41
+ lpaQuestionnaireValidationDetails: ['cupidatat dolore in', 'officia in nostrud non', 'eu amet velit labore aute'],
42
+ lpaStatement: 'ipsum consectetur labore pariatur',
43
+ caseWithdrawnDate: '1941-07-27T04:17:40.0Z',
44
+ caseTransferredDate: null,
45
+ transferredCaseClosedDate: null,
46
+ caseDecisionOutcomeDate: '1916-07-25T07:02:27.0Z',
47
+ caseDecisionPublishedDate: null,
48
+ caseDecisionOutcome: 'invalid',
49
+ caseCompletedDate: '1921-06-04T06:12:04.0Z',
50
+ enforcementNotice: null,
51
+ applicationReference: 'consequat ullamco in aute amet',
52
+ applicationDate: '1910-07-16T04:24:14.0Z',
53
+ applicationDecision: 'not_received',
54
+ applicationDecisionDate: null,
55
+ caseSubmissionDueDate: null,
56
+ siteAddressLine1: 'dolore mollit',
57
+ siteAddressLine2: null,
58
+ siteAddressTown: 'in',
59
+ siteAddressCounty: 'ut incididunt velit in',
60
+ siteAddressPostcode: 'ut',
61
+ siteAccessDetails: ['ullamco', 'elit in', 'velit officia pariatur mollit', 'nostrud ex culpa'],
62
+ siteSafetyDetails: null,
63
+ siteAreaSquareMetres: 69381079.34849802,
64
+ floorSpaceSquareMetres: null,
65
+ isCorrectAppealType: null,
66
+ isGreenBelt: false,
67
+ inConservationArea: null,
68
+ ownsAllLand: null,
69
+ ownsSomeLand: null,
70
+ knowsOtherOwners: null,
71
+ knowsAllOwners: null,
72
+ advertisedAppeal: true,
73
+ notificationMethod: ['notice'],
74
+ ownersInformed: null,
75
+ originalDevelopmentDescription: 'est',
76
+ changedDevelopmentDescription: null,
77
+ newConditionDetails: null,
78
+ nearbyCaseReferences: ['veniam voluptate incididunt Excepteur'],
79
+ neighbouringSiteAddresses: [
80
+ {
81
+ neighbouringSiteAddressLine1: 'laborum',
82
+ neighbouringSiteAddressLine2: null,
83
+ neighbouringSiteAddressTown: 'aute ipsum dolore',
84
+ neighbouringSiteAddressCounty: null,
85
+ neighbouringSiteAddressPostcode: 'dolor ipsum anim fugiat',
86
+ neighbouringSiteAccessDetails: 'reprehenderit mollit Duis exercitation',
87
+ neighbouringSiteSafetyDetails: null
88
+ }
89
+ ],
90
+ reasonForNeighbourVisits: null,
91
+ affectedListedBuildingNumbers: ['tempor adipisicing in'],
92
+ changedListedBuildingNumbers: null,
93
+ preserveGrantLoan: true,
94
+ consultHistoricEngland: false,
95
+ appellantCostsAppliedFor: null,
96
+ lpaCostsAppliedFor: null,
97
+ agriculturalHolding: null,
98
+ tenantAgriculturalHolding: null,
99
+ otherTenantsAgriculturalHolding: null,
100
+ informedTenantsAgriculturalHolding: true,
101
+ appellantProcedurePreference: 'hearing',
102
+ appellantProcedurePreferenceDetails: null,
103
+ appellantProcedurePreferenceDuration: null,
104
+ appellantProcedurePreferenceWitnessCount: null,
105
+ statusPlanningObligation: 'cillum proident fugiat ex quis',
106
+ affectsScheduledMonument: true,
107
+ hasProtectedSpecies: true,
108
+ isAonbNationalLandscape: null,
109
+ designatedSitesNames: null,
110
+ isGypsyOrTravellerSite: false,
111
+ isPublicRightOfWay: true,
112
+ eiaEnvironmentalImpactSchedule: 'schedule-1',
113
+ eiaDevelopmentDescription: 'agriculture-aquaculture',
114
+ eiaSensitiveAreaDetails: 'dolore non anim ut deserunt',
115
+ eiaColumnTwoThreshold: null,
116
+ eiaScreeningOpinion: true,
117
+ eiaRequiresEnvironmentalStatement: null,
118
+ eiaCompletedEnvironmentalStatement: null,
119
+ hasStatutoryConsultees: true,
120
+ consultedBodiesDetails: null,
121
+ hasInfrastructureLevy: null,
122
+ isInfrastructureLevyFormallyAdopted: null,
123
+ infrastructureLevyAdoptedDate: null,
124
+ infrastructureLevyExpectedDate: null,
125
+ lpaProcedurePreference: null,
126
+ lpaProcedurePreferenceDetails: null,
127
+ lpaProcedurePreferenceDuration: 43495666.11228904,
128
+ caseworkReason: 'sit ipsum',
129
+ importantInformation: null,
130
+ jurisdiction: null,
131
+ redeterminedIndicator: null,
132
+ dateCostsReportDespatched: '1951-10-17T06:20:56.0Z',
133
+ dateNotRecoveredOrDerecovered: '1965-01-28T14:22:43.0Z',
134
+ dateRecovered: null,
135
+ originalCaseDecisionDate: '1969-03-09T16:29:08.0Z',
136
+ targetDate: null,
137
+ appellantCommentsSubmittedDate: '1907-11-20T13:42:48.0Z',
138
+ appellantStatementSubmittedDate: null,
139
+ appellantProofsSubmittedDate: '1940-11-26T21:04:12.0Z',
140
+ finalCommentsDueDate: '1945-08-08T17:44:32.0Z',
141
+ interestedPartyRepsDueDate: null,
142
+ lpaCommentsSubmittedDate: '1941-03-28T08:08:45.0Z',
143
+ lpaProofsSubmittedDate: '1949-02-17T05:01:26.0Z',
144
+ lpaStatementSubmittedDate: null,
145
+ proofsOfEvidenceDueDate: '1945-06-24T01:14:05.0Z',
146
+ siteNoticesSentDate: '1904-03-09T08:52:39.0Z',
147
+ statementDueDate: null,
148
+ numberOfResidencesNetChange: 59800248.893144846,
149
+ siteGridReferenceEasting: '357144',
150
+ siteGridReferenceNorthing: '400534',
151
+ siteViewableFromRoad: null,
152
+ siteWithinSSSI: null,
153
+ typeOfPlanningApplication: 'full-appeal',
154
+ developmentType: 'other-minor',
155
+ statementOfCommonGroundDueDate: '1919-10-16T12:35:55.0Z',
156
+ planningObligationDueDate: '1899-04-25T22:23:18.0Z'
157
+ };
158
+
159
+ describe(schema, () => {
160
+ const schemas = loadAllSchemasSync();
161
+ const flatSchemas = Object.values(schemas).reduce((a, c) => ({ ...a, ...c }), {});
162
+ const ajv = new Ajv({ schemas: flatSchemas, allErrors: true });
163
+ addFormats(ajv);
164
+
165
+ it('should allow valid schema', () => {
166
+ const test = structuredClone(appealS78);
167
+ const validationResult = ajv.validate(schema, test);
168
+ assert.strictEqual(validationResult, true);
169
+ });
170
+
171
+ it('should enforce eastings-northings pattern', () => {
172
+ const invalidPatterns = [
173
+ { easting: 'abc123', northing: '400534', description: 'easting with letters' },
174
+ { easting: '1234567', northing: '400534', description: 'easting too long' },
175
+ { easting: '12345', northing: '400534', description: 'easting too short' },
176
+ { easting: '357144', northing: 'xyz123', description: 'northing with letters' },
177
+ { easting: '357144', northing: '1234567', description: 'northing too long' },
178
+ { easting: '357144', northing: '12345', description: 'northing too short' },
179
+ { easting: '', northing: '400534', description: 'empty easting' },
180
+ { easting: '357144', northing: '', description: 'empty northing' }
181
+ ];
182
+
183
+ for (const pattern of invalidPatterns) {
184
+ const test = structuredClone(appealS78);
185
+ test.siteGridReferenceEasting = pattern.easting;
186
+ test.siteGridReferenceNorthing = pattern.northing;
187
+
188
+ const validationResult = ajv.validate(schema, test);
189
+ assert.strictEqual(validationResult, false, `Expected validation to fail for ${pattern.description}`);
190
+ }
191
+ });
192
+
193
+ it('should allow only eastings-northings', () => {
194
+ const test = structuredClone(appealS78);
195
+ test.siteAddressPostcode = undefined;
196
+ test.siteAddressLine1 = null;
197
+ test.siteAddressTown = null;
198
+ const validationResult = ajv.validate(schema, test);
199
+ assert.strictEqual(validationResult, true);
200
+ });
201
+
202
+ it('should allow only site address', () => {
203
+ const test = structuredClone(appealS78);
204
+ test.siteGridReferenceEasting = undefined;
205
+ test.siteGridReferenceNorthing = null;
206
+ const validationResult = ajv.validate(schema, test);
207
+ assert.strictEqual(validationResult, true);
208
+ });
209
+
210
+ it('should enforce either site address or easting-northing', () => {
211
+ const test = structuredClone(appealS78);
212
+ test.siteAddressPostcode = undefined;
213
+ test.siteAddressLine1 = null;
214
+ test.siteAddressTown = null;
215
+ test.siteGridReferenceEasting = undefined;
216
+ test.siteGridReferenceNorthing = null;
217
+ const validationResult = ajv.validate(schema, test);
218
+ assert.strictEqual(validationResult, false);
219
+ });
220
+
221
+ it('should allow additional props', () => {
222
+ const test = structuredClone(appealS78);
223
+ test.test = 1; // additional unknown prop allowed
224
+ const validationResult = ajv.validate(schema, test);
225
+ assert.strictEqual(validationResult, true);
226
+ });
227
+ });