Merged PR 2399: Adds characterization coverage and documentation for CRM query field profile

Related work items: #23754
This commit is contained in:
Robert Bond
2026-06-18 08:04:36 +00:00
parent a6941a8a06
commit c84ff3fff9
4 changed files with 1564 additions and 0 deletions
@@ -0,0 +1,456 @@
const fs = require("fs");
const path = require("path");
const vm = require("vm");
const assert = require("assert");
const rootDir = path.resolve(__dirname, "..", "..");
const loadSelectQueryTypesModule = (relayPath) => {
const filePath = path.join(rootDir, "actions", "selectQueryTypes.js");
let source = fs.readFileSync(filePath, "utf8");
source = source.replace(
/export const\s+getSelectQuery\s*=\s*/,
"const getSelectQuery = "
);
source += `
module.exports = {
getSelectQuery
};
`;
const context = {
module: { exports: {} },
exports: {},
require,
process: {
env: {
RELAYPATH: relayPath
}
}
};
vm.runInNewContext(source, context, { filename: filePath });
return context.module.exports;
};
const tests = [];
const test = (name, fn) => tests.push({ name, fn });
const splitFields = (query) => {
assert.ok(
query.startsWith("&$select="),
`Expected query to start with &$select= but received: ${query}`
);
return query
.replace(/^&\$select=/, "")
.split(",")
.map((field) => field.trim())
.filter(Boolean);
};
const getFieldSet = (appealTypeName, relayPath) =>
new Set(
splitFields(
loadSelectQueryTypesModule(relayPath).getSelectQuery(appealTypeName)
)
);
const assertHasFields = (fieldSet, expectedFields, label) => {
for (const field of expectedFields) {
assert.ok(fieldSet.has(field), `${label}: expected field \`${field}\``);
}
};
test("planning-style near-clones preserve a shared base cluster while retaining intentional representation-field differences", () => {
const planningConditions = getFieldSet("pinswg_planningconditionss73s79s");
const planningObligation = getFieldSet(
"pinswg_planningobligationappeals106s"
);
const enforcement = getFieldSet("pinswg_enforcementnoticeappeals174s");
const sharedPlanningCluster = [
"modifiedon",
"_pinswg_appellant_value",
"pinswg_name",
"pinswg_siteaddressline1",
"pinswg_siteaddressline2",
"pinswg_siteaddresspostcode",
"pinswg_siteaddresstown",
"_pinswg_associatedlpa_value",
"pinswg_casedecisiondate",
"pinswg_dateeventrequested",
"pinswg_finalcommentsduedate",
"pinswg_procedure",
"pinswg_questionnaireduedate",
"pinswg_startdate",
"pinswg_statementduedate",
"statuscode"
];
for (const [label, fields] of [
["Planning conditions", planningConditions],
["Planning obligation", planningObligation],
["Enforcement", enforcement]
]) {
assertHasFields(fields, sharedPlanningCluster, label);
}
assert.ok(
planningConditions.has("pinswg_otherpartiesstatement") &&
!planningConditions.has("pinswg_otherpartiesstatements"),
"Planning conditions should preserve singular other-parties field variant"
);
assert.ok(
planningObligation.has("pinswg_otherpartiesstatements") &&
!planningObligation.has("pinswg_otherpartiesstatement"),
"Planning obligation should preserve plural other-parties field variant"
);
assert.ok(
enforcement.has("pinswg_startdateoftheevent") &&
!enforcement.has("pinswg_startdateofevent"),
"Enforcement should preserve its current event-date field variant"
);
});
test("ROW and Hedges preserve a shared specialist/date/representation near-clone cluster", () => {
const rows = getFieldSet("pinswg_rows");
const hedges = getFieldSet(
"pinswg_hedgeshedgerowstreepreservationreplacems"
);
const sharedRowHedgesCluster = [
"pinswg_specialistcaseprocess",
"modifiedon",
"_pinswg_appellant_value",
"pinswg_name",
"_pinswg_associatedlpa_value",
"pinswg_casedecisiondate",
"pinswg_finalcommentsduedate",
"pinswg_otherpartiesstatement",
"pinswg_procedure",
"pinswg_proofsofevidencewrittenstatementsofeviden",
"pinswg_questionnaireduedate",
"pinswg_relevantauthorityname",
"pinswg_startdate",
"pinswg_startdateoftheevent",
"pinswg_typeofevent",
"pinswg_statementduedate",
"statuscode"
];
assertHasFields(rows, sharedRowHedgesCluster, "ROW near-clone cluster");
assertHasFields(
hedges,
sharedRowHedgesCluster,
"Hedges near-clone cluster"
);
assert.ok(
rows.has("pinswg_detailedeiascreeningrequired") &&
!rows.has("pinswg_detailedeiascreening"),
"ROW should preserve detailed EIA screening required variant"
);
assert.ok(
hedges.has("pinswg_detailedeiascreening") &&
!hedges.has("pinswg_detailedeiascreeningrequired"),
"Hedges should preserve detailed EIA screening variant without accidental normalization"
);
});
test("Advert specialist divergence is preserved against ROW canonical specialist-process selection", () => {
const adverts = getFieldSet("pinswg_advertses");
const rows = getFieldSet("pinswg_rows");
assert.ok(
adverts.has("pinswg_speacialistcaseprocess") &&
!adverts.has("pinswg_specialistcaseprocess"),
"Adverts should preserve misspelled specialist-process field only"
);
assert.ok(
rows.has("pinswg_specialistcaseprocess") &&
!rows.has("pinswg_speacialistcaseprocess"),
"ROW should preserve canonical specialist-process field only"
);
assertHasFields(
adverts,
[
"pinswg_finalcommentsduedate",
"pinswg_questionnaireduedate",
"pinswg_statementduedate",
"pinswg_startdate",
"pinswg_startdateoftheevent"
],
"Adverts specialist divergence support cluster"
);
assertHasFields(
rows,
[
"pinswg_finalcommentsduedate",
"pinswg_questionnaireduedate",
"pinswg_statementduedate",
"pinswg_startdate",
"pinswg_startdateoftheevent"
],
"ROW specialist divergence support cluster"
);
});
test("infrastructure near-clones preserve shared milestone concepts and schema-specific divergences", () => {
const dns = getFieldSet("pinswg_dnses");
const harbour = getFieldSet("pinswg_harbourrevisionorders");
const transport = getFieldSet("pinswg_transportandworkacts");
const electricity = getFieldSet("pinswg_electricityacts");
const sharedInfrastructureCluster = [
"pinswg_eiarequired",
"pinswg_name",
"pinswg_addressline1",
"pinswg_addressline2",
"pinswg_postcode",
"pinswg_addresstown",
"pinswg_applicationacceptedasvalid",
"pinswg_confirmrequesttovaryapplication",
"pinswg_dateeventrequested",
"pinswg_dateofsubmissionofapplication",
"pinswg_dateprojectpublishedonwebsite",
"pinswg_deadlineforsubmissionofapplication",
"pinswg_endofrepresentationperiod",
"pinswg_inspectorreportsubmittedtowelshgovernment",
"pinswg_projectlocation",
"pinswg_recommendation",
"pinswg_rejectrequesttovaryapplication",
"pinswg_reportdueby",
"pinswg_suspensiondates",
"pinswg_validnoticeofintentiontosubmitanapplicati",
"pinswg_webaddress",
"pinswg_withdrawndate",
"pinswg_writtenacceptanceofnotification",
"pinswg_startdateofevent",
"pinswg_typeofevent",
"statuscode"
];
for (const [label, fields] of [
["DNS", dns],
["Harbour", harbour],
["Transport", transport],
["Electricity", electricity]
]) {
assertHasFields(fields, sharedInfrastructureCluster, label);
}
assert.ok(
dns.has("pinswg_projectdescription") &&
!dns.has("pinswg_projectdiscription"),
"DNS should preserve canonical project description"
);
assert.ok(
harbour.has("pinswg_projectdiscription") &&
!harbour.has("pinswg_projectdescription"),
"Harbour should preserve misspelled project description variant"
);
assert.ok(
transport.has("pinswg_projectdescription") &&
!transport.has("pinswg_projectdiscription"),
"Transport should preserve canonical project description field"
);
assert.ok(
dns.has("pinswg_suspensionstartdates") &&
!dns.has("pinswg_suspensionstartdate"),
"DNS should preserve plural suspension start field"
);
for (const [label, fields] of [
["Harbour", harbour],
["Transport", transport]
]) {
assert.ok(
fields.has("pinswg_suspensionstartdate") &&
!fields.has("pinswg_suspensionstartdates"),
`${label} should preserve singular suspension start field variant`
);
}
assert.ok(
dns.has("pinswg_anticipatedgridreferenceeastingtext") &&
dns.has("pinswg_anticipatedgridreferencenorthingtext"),
"DNS should preserve grid reference fields"
);
assert.ok(
harbour.has("pinswg_anticipatedgridreferenceeastingtext") &&
harbour.has("pinswg_anticipatedgridreferencenorthingtext"),
"Harbour should preserve grid reference fields"
);
assert.ok(
!electricity.has("pinswg_anticipatedgridreferenceeastingtext") &&
!electricity.has("pinswg_anticipatedgridreferencenorthingtext"),
"Electricity should preserve current absence of grid reference fields"
);
});
test("representation-support cluster preserves questionnaire, statement, final-comments, and proof/other-parties variants", () => {
const rows = getFieldSet("pinswg_rows");
const planningObligation = getFieldSet(
"pinswg_planningobligationappeals106s"
);
const householder = getFieldSet("pinswg_householderappealhases");
const commonLand = getFieldSet("pinswg_commonlands");
assertHasFields(
rows,
[
"pinswg_questionnaireduedate",
"pinswg_statementduedate",
"pinswg_finalcommentsduedate",
"pinswg_proofsofevidencewrittenstatementsofeviden",
"pinswg_otherpartiesstatement"
],
"ROW representation-support cluster"
);
assertHasFields(
planningObligation,
[
"pinswg_questionnaireduedate",
"pinswg_statementduedate",
"pinswg_finalcommentsduedate",
"pinswg_otherpartiesstatements"
],
"Planning obligation representation-support cluster"
);
assertHasFields(
householder,
[
"pinswg_questionnaireduedate",
"pinswg_statementduedate",
"pinswg_finalcommentsduedate",
"pinswg_otherpartiesstmt"
],
"Householder representation-support cluster"
);
assertHasFields(
commonLand,
[
"pinswg_questionnaireduedate",
"pinswg_statementsduedate",
"pinswg_finalcommentsduedate",
"pinswg_proofsofevidencewrittenstatementsofeviden",
"pinswg_otherpartiesstatement"
],
"Common land representation-support cluster"
);
assert.ok(
commonLand.has("pinswg_statementsduedate") &&
!commonLand.has("pinswg_statementduedate"),
"Common land should preserve plural statement-due-date variant"
);
});
test("event-date cluster preserves coexistence of start-date/time variants across representative bundles", () => {
const callIns = getFieldSet("pinswg_callinss77s");
const adverts = getFieldSet("pinswg_advertses");
const planningS78Dev = getFieldSet(
"pinswg_planningappeals78s",
"dev-pedw-hc"
);
const listedBuilding = getFieldSet(
"pinswg_listedbuildingandconservationareaconsens"
);
const commonLand = getFieldSet("pinswg_commonlands");
assert.ok(
callIns.has("pinswg_startdateofevent") &&
!callIns.has("pinswg_startdateoftheevent"),
"Call-ins should preserve `pinswg_startdateofevent` variant"
);
assert.ok(
adverts.has("pinswg_startdateoftheevent") &&
!adverts.has("pinswg_startdateofevent"),
"Adverts should preserve `pinswg_startdateoftheevent` variant"
);
assert.ok(
planningS78Dev.has("pinswg_startdatetimeiftheevent"),
"S78 should preserve datetime event variant"
);
assert.ok(
listedBuilding.has("pinswg_starttimeofevent") &&
!listedBuilding.has("pinswg_starttimeoftheevent"),
"Listed building should preserve `pinswg_starttimeofevent` variant"
);
assert.ok(
commonLand.has("pinswg_starttimeoftheevent") &&
!commonLand.has("pinswg_starttimeofevent"),
"Common land should preserve `pinswg_starttimeoftheevent` variant"
);
});
test("authority and LPA cluster preserves current coexistence of local, associated, and relevant authority fields", () => {
const planningS78Dev = getFieldSet(
"pinswg_planningappeals78s",
"dev-pedw-hc"
);
const rows = getFieldSet("pinswg_rows");
const dns = getFieldSet("pinswg_dnses");
assert.ok(
planningS78Dev.has("_pinswg_localplanningauthority_value") &&
!planningS78Dev.has("_pinswg_associatedlpa_value") &&
!planningS78Dev.has("pinswg_relevantauthorityname"),
"S78 should preserve local-planning-authority-only behaviour"
);
assert.ok(
rows.has("_pinswg_associatedlpa_value") &&
rows.has("pinswg_relevantauthorityname") &&
!rows.has("_pinswg_localplanningauthority_value"),
"ROW should preserve overlap of associated LPA and relevant authority"
);
assert.ok(
dns.has("_pinswg_associatedlpa_value") &&
!dns.has("pinswg_relevantauthorityname") &&
!dns.has("_pinswg_localplanningauthority_value"),
"DNS should preserve associated-LPA-only authority behaviour"
);
});
const run = async () => {
let passed = 0;
for (const currentTest of tests) {
await currentTest.fn();
passed += 1;
}
console.log(
`Phase 22 select-query-types duplicated-cluster tests passed (${passed}/${tests.length}).`
);
};
module.exports = run;
if (require.main === module) {
run().catch((error) => {
console.error(error);
process.exit(1);
});
}
@@ -0,0 +1,395 @@
const fs = require("fs");
const path = require("path");
const vm = require("vm");
const assert = require("assert");
const rootDir = path.resolve(__dirname, "..", "..");
const loadSelectQueryTypesModule = (relayPath) => {
const filePath = path.join(rootDir, "actions", "selectQueryTypes.js");
let source = fs.readFileSync(filePath, "utf8");
source = source.replace(
/export const\s+getSelectQuery\s*=\s*/,
"const getSelectQuery = "
);
source += `
module.exports = {
getSelectQuery
};
`;
const context = {
module: { exports: {} },
exports: {},
require,
process: {
env: {
RELAYPATH: relayPath
}
}
};
vm.runInNewContext(source, context, { filename: filePath });
return context.module.exports;
};
const tests = [];
const test = (name, fn) => tests.push({ name, fn });
const splitFields = (query) => {
assert.ok(
query.startsWith("&$select="),
`Expected query to start with &$select= but received: ${query}`
);
return query
.replace(/^&\$select=/, "")
.split(",")
.map((field) => field.trim())
.filter(Boolean);
};
const assertIncludesAll = (fields, requiredFields, message) => {
for (const field of requiredFields) {
assert.ok(
fields.includes(field),
`${message}: expected field \`${field}\` to be included`
);
}
};
test("Planning S78 bundle preserves base, typo, S78-specific, and relaypath-dependent fields", () => {
const devMod = loadSelectQueryTypesModule("dev-pedw-hc");
const nonDevMod = loadSelectQueryTypesModule("prod-like");
const devFields = splitFields(
devMod.getSelectQuery("pinswg_planningappeals78s")
);
const nonDevFields = splitFields(
nonDevMod.getSelectQuery("pinswg_planningappeals78s")
);
assertIncludesAll(
devFields,
[
"pinswg_eiarequired",
"modifiedon",
"_pinswg_appellant_value",
"pinswg_name",
"pinswg_siteaddressline1",
"pinswg_siteaddresspostcode",
"pinswg_siteaddresscounty",
"_pinswg_localplanningauthority_value",
"pinswg_casedecisiondate",
"pinswg_dicision",
"pinswg_questionnaireduedate",
"pinswg_startdate",
"pinswg_statementduedate",
"pinswg_startdatetimeiftheevent",
"pinswg_representation_period_end_date",
"pinswg_extend_representation_date",
"pinswg_typeofevent",
"statuscode"
],
"S78 dev bundle"
);
assert.ok(
!devFields.includes("pinswg_developmentdescription"),
"S78 dev bundle should preserve current omission of extended appeal-form fields"
);
assertIncludesAll(
nonDevFields,
[
"pinswg_eiarequired",
"modifiedon",
"_pinswg_appellant_value",
"pinswg_name",
"pinswg_dicision",
"pinswg_startdatetimeiftheevent",
"pinswg_developmentdescription",
"pinswg_whyisinspectorneededonsite",
"pinswg_outlinehealthandsafetyissuesonsite",
"pinswg_additionalappealsmadedetails",
"pinswg_chosenprocedureexplanation",
"pinswg_dateofapplication",
"pinswg_lpaapplicationreference",
"pinswg_caseworkreason",
"pinswg_dateoflpadecision",
"pinswg_areaofsiteinhectaresdec",
"pinswg_floorspaceinsquaremeters",
"pinswg_ownershipcertificate",
"pinswg_siteviewablefromroad",
"pinswg_costappliedforindicator",
"pinswg_s106unilateralsubmitted"
],
"S78 non-dev bundle"
);
assert.ok(
!nonDevFields.includes("pinswg_representation_period_end_date"),
"S78 non-dev bundle should preserve current omission of dev-only representation-period fields"
);
});
test("DNS bundle preserves project, representation-window, and process fields", () => {
const { getSelectQuery } = loadSelectQueryTypesModule();
const fields = splitFields(getSelectQuery("pinswg_dnses"));
assertIncludesAll(
fields,
[
"pinswg_eiarequired",
"pinswg_anticipatedgridreferenceeastingtext",
"pinswg_anticipatedgridreferencenorthingtext",
"pinswg_name",
"pinswg_addressline1",
"pinswg_addresscounty",
"pinswg_applicationacceptedasvalid",
"pinswg_choiceofprocedure",
"pinswg_dateofdecision",
"pinswg_deadlineforsubmissionofapplication",
"pinswg_endofrepresentationperiod",
"pinswg_procedureconfirmed",
"pinswg_projectdescription",
"pinswg_projectlocation",
"pinswg_recommendation",
"pinswg_reportdueby",
"pinswg_suspensiondates",
"pinswg_suspensionenddates",
"pinswg_suspensionstartdates",
"pinswg_webaddress",
"pinswg_writtenacceptanceofnotification",
"_pinswg_dnsids_value",
"pinswg_startdateofevent",
"pinswg_typeofevent",
"statuscode"
],
"DNS bundle"
);
});
test("SIPS bundle preserves consultation and milestone fields", () => {
const { getSelectQuery } = loadSelectQueryTypesModule();
const fields = splitFields(getSelectQuery("pinswg_sipses"));
assertIncludesAll(
fields,
[
"pinswg_casedeadline",
"_pinswg_projecttype_value",
"pinswg_eiarequired",
"pinswg_anticipatedgridrefeasting",
"pinswg_anticipatedgridrefnorthing",
"_pinswg_appellant_value",
"pinswg_name",
"_pinswg_associatedlpa_value",
"pinswg_choiceofprocedure",
"pinswg_projectdescription",
"pinswg_projectlocation",
"_pinswg_sipscase_value",
"pinswg_validnoticeofintentiontosubmit",
"pinswg_deadlineforsubmissionofapplication",
"pinswg_screeningstartdate",
"pinswg_eiatargetdate",
"pinswg_scopingstartdate",
"pinswg_scopingtargetdate",
"pinswg_scopingoutcomeissueddate",
"pinswg_consultationopen",
"pinswg_consultationclose",
"pinswg_reportissuedtowelshministers",
"pinswg_decisionissuedtoapplicant",
"pinswg_redeterminationconsultationdeadline"
],
"SIPS bundle"
);
});
test("ROW bundle preserves canonical specialist-process field and date/representation fields", () => {
const { getSelectQuery } = loadSelectQueryTypesModule();
const fields = splitFields(getSelectQuery("pinswg_rows"));
assertIncludesAll(
fields,
[
"pinswg_detailedeiascreeningrequired",
"pinswg_specialistcaseprocess",
"modifiedon",
"_pinswg_appellant_value",
"pinswg_name",
"_pinswg_associatedlpa_value",
"pinswg_casedecisiondate",
"pinswg_finalcommentsduedate",
"pinswg_otherpartiesstatement",
"pinswg_procedure",
"pinswg_proofsofevidencewrittenstatementsofeviden",
"pinswg_questionnaireduedate",
"pinswg_relevantauthorityname",
"pinswg_startdate",
"pinswg_startdateoftheevent",
"pinswg_typeofevent",
"pinswg_statementduedate",
"statuscode"
],
"ROW bundle"
);
assert.ok(
!fields.includes("pinswg_speacialistcaseprocess"),
"ROW bundle should preserve current absence of misspelled specialist-process field"
);
});
test("Adverts bundle preserves misspelled specialist-process field and representation fields", () => {
const { getSelectQuery } = loadSelectQueryTypesModule();
const fields = splitFields(getSelectQuery("pinswg_advertses"));
assertIncludesAll(
fields,
[
"pinswg_detailedeiascreeningrequired",
"pinswg_speacialistcaseprocess",
"modifiedon",
"_pinswg_appellant_value",
"pinswg_name",
"_pinswg_associatedlpa_value",
"pinswg_casedecisiondate",
"pinswg_dateeventrequested",
"pinswg_procedure",
"pinswg_questionnaireduedate",
"pinswg_startdateoftheevent",
"pinswg_startdate",
"pinswg_otherpartiesstatement",
"pinswg_finalcommentsduedate",
"pinswg_proofsofevidencewrittenstatementsofeviden",
"pinswg_statementduedate",
"statuscode"
],
"Adverts bundle"
);
assert.ok(
!fields.includes("pinswg_specialistcaseprocess"),
"Adverts bundle should preserve current absence of canonical specialist-process field"
);
});
test("Householder bundle preserves reduced field set and other-parties variant", () => {
const { getSelectQuery } = loadSelectQueryTypesModule();
const fields = splitFields(getSelectQuery("pinswg_householderappealhases"));
assertIncludesAll(
fields,
[
"pinswg_eiarequired",
"modifiedon",
"_pinswg_appellant_value",
"pinswg_name",
"pinswg_siteaddressline1",
"pinswg_siteaddresspostcode",
"_pinswg_associatedlpa_value",
"pinswg_casedecisiondate",
"pinswg_dateeventrequested",
"pinswg_decision",
"pinswg_finalcommentsduedate",
"pinswg_otherpartiesstmt",
"pinswg_procedure",
"pinswg_questionnaireduedate",
"pinswg_startdate",
"pinswg_statementduedate",
"statuscode"
],
"Householder bundle"
);
assert.ok(
!fields.includes("pinswg_startdateoftheevent") &&
!fields.includes("pinswg_startdateofevent"),
"Householder bundle should preserve current omission of event-start fields"
);
});
test("Infrastructure-style harbour bundle preserves project/date fields and schema variants", () => {
const { getSelectQuery } = loadSelectQueryTypesModule();
const fields = splitFields(getSelectQuery("pinswg_harbourrevisionorders"));
assertIncludesAll(
fields,
[
"pinswg_eiarequired",
"pinswg_anticipatedgridreferenceeastingtext",
"pinswg_anticipatedgridreferencenorthingtext",
"pinswg_name",
"pinswg_addressline1",
"pinswg_addresscounty",
"pinswg_applicationacceptedasvalid",
"pinswg_choiceofprocedure",
"pinswg_dateofdecision",
"pinswg_endofrepresentationperiod",
"pinswg_projectdiscription",
"pinswg_projectlocation",
"pinswg_suspensionstartdate",
"pinswg_suspensionenddates",
"pinswg_validnoticeofintentiontosubmitanapplicati",
"pinswg_writtenacceptanceofnotification",
"pinswg_startdateofevent",
"pinswg_typeofevent",
"statuscode"
],
"Harbour bundle"
);
});
test("Minimal bundles preserve current nonvalidation and LDP behaviour", () => {
const { getSelectQuery } = loadSelectQueryTypesModule();
const nonValidationFields = splitFields(
getSelectQuery("pinswg_nonvalidations")
);
assertIncludesAll(
nonValidationFields,
[
"modifiedon",
"_pinswg_appellant_value",
"pinswg_name",
"pinswg_siteaddressline1",
"pinswg_siteaddressline2",
"pinswg_siteaddresspostcode",
"pinswg_siteaddresstown",
"_pinswg_associatedlpa_value",
"statuscode"
],
"Nonvalidation bundle"
);
assert.strictEqual(
nonValidationFields.includes("pinswg_casedecisiondate"),
false,
"Nonvalidation bundle should preserve current omission of decision-date fields"
);
const ldpFields = splitFields(getSelectQuery("pinswg_ldps"));
assert.deepStrictEqual(ldpFields, ["modifiedon", "pinswg_name"]);
});
const run = async () => {
let passed = 0;
for (const currentTest of tests) {
await currentTest.fn();
passed += 1;
}
console.log(
`Phase 22 select-query-types field bundle tests passed (${passed}/${tests.length}).`
);
};
module.exports = run;
if (require.main === module) {
run().catch((error) => {
console.error(error);
process.exit(1);
});
}
@@ -0,0 +1,405 @@
const fs = require("fs");
const path = require("path");
const vm = require("vm");
const assert = require("assert");
const rootDir = path.resolve(__dirname, "..", "..");
const loadSelectQueryTypesModule = (relayPath) => {
const filePath = path.join(rootDir, "actions", "selectQueryTypes.js");
let source = fs.readFileSync(filePath, "utf8");
source = source.replace(
/export const\s+getSelectQuery\s*=\s*/,
"const getSelectQuery = "
);
source += `
module.exports = {
getSelectQuery
};
`;
const context = {
module: { exports: {} },
exports: {},
require,
process: {
env: {
RELAYPATH: relayPath
}
}
};
vm.runInNewContext(source, context, { filename: filePath });
return context.module.exports;
};
const tests = [];
const test = (name, fn) => tests.push({ name, fn });
const splitFields = (query) => {
assert.ok(
query.startsWith("&$select="),
`Expected query to start with &$select= but received: ${query}`
);
return query
.replace(/^&\$select=/, "")
.split(",")
.map((field) => field.trim())
.filter(Boolean);
};
const getFieldSet = (appealTypeName, relayPath) =>
new Set(
splitFields(
loadSelectQueryTypesModule(relayPath).getSelectQuery(appealTypeName)
)
);
const assertHasFields = (fieldSet, expectedFields, label) => {
for (const field of expectedFields) {
assert.ok(fieldSet.has(field), `${label}: expected field \`${field}\``);
}
};
test("planning-style family preserves common base, location, decision, and status fields across representative bundles", () => {
const s78Dev = getFieldSet("pinswg_planningappeals78s", "dev-pedw-hc");
const rows = getFieldSet("pinswg_rows");
const householder = getFieldSet("pinswg_householderappealhases");
const planningBaseFamily = [
"modifiedon",
"_pinswg_appellant_value",
"pinswg_name",
"pinswg_dateeventrequested",
"statuscode"
];
for (const [label, fields] of [
["S78 dev", s78Dev],
["ROW", rows],
["Householder", householder]
]) {
assertHasFields(fields, planningBaseFamily, label);
}
assertHasFields(
s78Dev,
[
"pinswg_siteaddressline1",
"pinswg_siteaddressline2",
"pinswg_siteaddresspostcode",
"pinswg_siteaddresstown",
"pinswg_siteaddresscounty",
"pinswg_casedecisiondate",
"pinswg_dicision"
],
"S78 dev planning family"
);
assertHasFields(
rows,
[
"pinswg_siteaddressline1",
"pinswg_siteaddressline2",
"pinswg_siteaddresspostcode",
"pinswg_siteaddresstown",
"pinswg_casedecisiondate",
"pinswg_decision"
],
"ROW planning family"
);
assertHasFields(
householder,
[
"pinswg_siteaddressline1",
"pinswg_siteaddressline2",
"pinswg_siteaddresspostcode",
"pinswg_siteaddresstown",
"pinswg_casedecisiondate",
"pinswg_decision"
],
"Householder planning family"
);
});
test("representation-window family preserves current start and end date variants without normalization", () => {
const rows = getFieldSet("pinswg_rows");
const enforcementListed = getFieldSet(
"pinswg_enforcementlistedbuildingconservationaps"
);
const dns = getFieldSet("pinswg_dnses");
const callIns = getFieldSet("pinswg_callinss77s");
assertHasFields(
rows,
[
"pinswg_startdate",
"pinswg_statementduedate",
"pinswg_finalcommentsduedate"
],
"ROW representation-window family"
);
assertHasFields(
enforcementListed,
[
"pinswg_startdates",
"pinswg_statementduedate",
"pinswg_finalcommentsduedate"
],
"Enforcement listed representation-window family"
);
assertHasFields(
dns,
[
"pinswg_applicationacceptedasvalid",
"pinswg_endofrepresentationperiod"
],
"DNS representation-window family"
);
assertHasFields(
callIns,
[
"pinswg_startdate",
"pinswg_statementsduedate",
"pinswg_finalcommentsduedate"
],
"Call-ins representation-window family"
);
assert.ok(
!dns.has("pinswg_startdate") && !dns.has("pinswg_startdates"),
"DNS should preserve infrastructure-style start-date variant rather than planning-style start fields"
);
});
test("specialist-process family preserves intentional field-variant divergence across bundles", () => {
const rows = getFieldSet("pinswg_rows");
const adverts = getFieldSet("pinswg_advertses");
const hedges = getFieldSet(
"pinswg_hedgeshedgerowstreepreservationreplacems"
);
const householder = getFieldSet("pinswg_householderappealhases");
assert.ok(
rows.has("pinswg_specialistcaseprocess") &&
!rows.has("pinswg_speacialistcaseprocess"),
"ROW should preserve canonical-only specialist-process selection"
);
assert.ok(
adverts.has("pinswg_speacialistcaseprocess") &&
!adverts.has("pinswg_specialistcaseprocess"),
"Adverts should preserve misspelled-only specialist-process selection"
);
assert.ok(
hedges.has("pinswg_specialistcaseprocess") &&
!hedges.has("pinswg_speacialistcaseprocess"),
"Hedges should preserve canonical-only specialist-process selection"
);
assert.ok(
!householder.has("pinswg_specialistcaseprocess") &&
!householder.has("pinswg_speacialistcaseprocess"),
"Householder should preserve absence of specialist-process fields"
);
});
test("infrastructure-style family preserves project-oriented fields and schema variants across representative bundles", () => {
const dns = getFieldSet("pinswg_dnses");
const harbour = getFieldSet("pinswg_harbourrevisionorders");
const electricity = getFieldSet("pinswg_electricityacts");
const commonInfrastructureFields = [
"pinswg_eiarequired",
"pinswg_name",
"pinswg_addressline1",
"pinswg_addresstown",
"pinswg_postcode",
"pinswg_applicationacceptedasvalid",
"pinswg_endofrepresentationperiod",
"pinswg_projectlocation",
"pinswg_recommendation",
"pinswg_reportdueby",
"pinswg_validnoticeofintentiontosubmitanapplicati",
"pinswg_writtenacceptanceofnotification",
"pinswg_startdateofevent",
"pinswg_typeofevent",
"statuscode"
];
for (const [label, fields] of [
["DNS", dns],
["Harbour", harbour],
["Electricity", electricity]
]) {
assertHasFields(fields, commonInfrastructureFields, label);
}
assert.ok(
dns.has("pinswg_projectdescription") &&
!dns.has("pinswg_projectdiscription"),
"DNS should preserve canonical project description field"
);
assert.ok(
harbour.has("pinswg_projectdiscription") &&
!harbour.has("pinswg_projectdescription"),
"Harbour should preserve misspelled project description variant"
);
assert.ok(
dns.has("pinswg_suspensionstartdates") &&
!dns.has("pinswg_suspensionstartdate"),
"DNS should preserve plural suspension start field"
);
assert.ok(
harbour.has("pinswg_suspensionstartdate") &&
!harbour.has("pinswg_suspensionstartdates"),
"Harbour should preserve singular suspension start field variant"
);
assert.ok(
electricity.has("modifiedon") && !dns.has("modifiedon"),
"Electricity should preserve current modifiedon overlap while DNS preserves its current omission"
);
});
test("authority and LPA family preserves current field distinctions rather than collapsing them", () => {
const s78Dev = getFieldSet("pinswg_planningappeals78s", "dev-pedw-hc");
const rows = getFieldSet("pinswg_rows");
const dns = getFieldSet("pinswg_dnses");
assert.ok(
s78Dev.has("_pinswg_localplanningauthority_value") &&
!s78Dev.has("_pinswg_associatedlpa_value"),
"S78 should preserve local-planning-authority field variant"
);
assert.ok(
rows.has("_pinswg_associatedlpa_value") &&
rows.has("pinswg_relevantauthorityname"),
"ROW should preserve overlap of associated LPA and relevant authority fields"
);
assert.ok(
dns.has("_pinswg_associatedlpa_value") &&
!dns.has("pinswg_relevantauthorityname"),
"DNS should preserve associated LPA without planning-style relevant-authority field"
);
});
test("consultation family is currently specific to SIPS-style profiles", () => {
const sips = getFieldSet("pinswg_sipses");
const dns = getFieldSet("pinswg_dnses");
const rows = getFieldSet("pinswg_rows");
assertHasFields(
sips,
["pinswg_consultationopen", "pinswg_consultationclose"],
"SIPS consultation family"
);
assert.ok(
!dns.has("pinswg_consultationopen") &&
!dns.has("pinswg_consultationclose") &&
!rows.has("pinswg_consultationopen") &&
!rows.has("pinswg_consultationclose"),
"Consultation fields should preserve their current absence from non-SIPS representative bundles"
);
});
test("minimal-profile family preserves intentionally small bundles and divergence from larger families", () => {
const nonValidation = getFieldSet("pinswg_nonvalidations");
const ldp = getFieldSet("pinswg_ldps");
const rows = getFieldSet("pinswg_rows");
assert.deepStrictEqual([...ldp], ["modifiedon", "pinswg_name"]);
assertHasFields(
nonValidation,
[
"modifiedon",
"_pinswg_appellant_value",
"pinswg_name",
"pinswg_siteaddressline1",
"pinswg_siteaddresspostcode",
"_pinswg_associatedlpa_value",
"statuscode"
],
"Nonvalidation minimal family"
);
assert.ok(
!nonValidation.has("pinswg_questionnaireduedate") &&
!nonValidation.has("pinswg_startdate") &&
!nonValidation.has("pinswg_applicationacceptedasvalid"),
"Nonvalidation should preserve absence of representation-window and questionnaire family fields"
);
assert.ok(
rows.size > nonValidation.size && nonValidation.size > ldp.size,
"Minimal bundles should preserve their intentionally smaller profiles relative to larger planning bundles"
);
});
test("family overlaps and divergences are preserved across representative bundles", () => {
const rows = getFieldSet("pinswg_rows");
const dns = getFieldSet("pinswg_dnses");
const sips = getFieldSet("pinswg_sipses");
const nonValidation = getFieldSet("pinswg_nonvalidations");
assert.ok(
rows.has("pinswg_startdate") && rows.has("pinswg_finalcommentsduedate"),
"Planning + representation overlap should be preserved for ROW"
);
assert.ok(
dns.has("pinswg_applicationacceptedasvalid") &&
dns.has("pinswg_endofrepresentationperiod") &&
dns.has("pinswg_projectlocation"),
"Infrastructure + representation overlap should be preserved for DNS"
);
assert.ok(
sips.has("pinswg_consultationopen") &&
sips.has("pinswg_consultationclose") &&
!sips.has("pinswg_finalcommentsduedate"),
"SIPS + consultation overlap and planning-style divergence should be preserved"
);
assert.ok(
!nonValidation.has("pinswg_projectlocation") &&
!nonValidation.has("pinswg_consultationopen") &&
!nonValidation.has("pinswg_questionnaireduedate"),
"Minimal profiles should preserve divergence from infrastructure, consultation, and richer planning families"
);
});
const run = async () => {
let passed = 0;
for (const currentTest of tests) {
await currentTest.fn();
passed += 1;
}
console.log(
`Phase 22 select-query-types field family tests passed (${passed}/${tests.length}).`
);
};
module.exports = run;
if (require.main === module) {
run().catch((error) => {
console.error(error);
process.exit(1);
});
}