@hobokengrace/n8n-nodes-pco 0.1.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.
- package/LICENSE.md +21 -0
- package/README.md +79 -0
- package/dist/credentials/PlanningCenterPatApi.credentials.d.ts +9 -0
- package/dist/credentials/PlanningCenterPatApi.credentials.js +84 -0
- package/dist/credentials/PlanningCenterPatApi.credentials.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/nodes/assets/api.svg +4 -0
- package/dist/nodes/assets/calendar.svg +4 -0
- package/dist/nodes/assets/check-ins.svg +4 -0
- package/dist/nodes/assets/current.svg +4 -0
- package/dist/nodes/assets/giving.svg +4 -0
- package/dist/nodes/assets/groups.svg +4 -0
- package/dist/nodes/assets/pco.svg +4 -0
- package/dist/nodes/assets/people.svg +4 -0
- package/dist/nodes/assets/publishing.svg +4 -0
- package/dist/nodes/assets/registrations.svg +4 -0
- package/dist/nodes/assets/services.svg +4 -0
- package/dist/nodes/assets/webhooks.svg +4 -0
- package/dist/nodes/generated/api/PlanningCenterApi.node.d.ts +16 -0
- package/dist/nodes/generated/api/PlanningCenterApi.node.js +745 -0
- package/dist/nodes/generated/api/PlanningCenterApi.node.js.map +1 -0
- package/dist/nodes/generated/api/api.svg +4 -0
- package/dist/nodes/generated/api/pco.svg +4 -0
- package/dist/nodes/generated/calendar/PlanningCenterCalendar.node.d.ts +305 -0
- package/dist/nodes/generated/calendar/PlanningCenterCalendar.node.js +33813 -0
- package/dist/nodes/generated/calendar/PlanningCenterCalendar.node.js.map +1 -0
- package/dist/nodes/generated/calendar/calendar.svg +4 -0
- package/dist/nodes/generated/calendar/pco.svg +4 -0
- package/dist/nodes/generated/check-ins/PlanningCenterCheckIns.node.d.ts +308 -0
- package/dist/nodes/generated/check-ins/PlanningCenterCheckIns.node.js +29142 -0
- package/dist/nodes/generated/check-ins/PlanningCenterCheckIns.node.js.map +1 -0
- package/dist/nodes/generated/check-ins/check-ins.svg +4 -0
- package/dist/nodes/generated/check-ins/pco.svg +4 -0
- package/dist/nodes/generated/current/PlanningCenterCurrent.node.d.ts +13 -0
- package/dist/nodes/generated/current/PlanningCenterCurrent.node.js +564 -0
- package/dist/nodes/generated/current/PlanningCenterCurrent.node.js.map +1 -0
- package/dist/nodes/generated/current/current.svg +4 -0
- package/dist/nodes/generated/current/pco.svg +4 -0
- package/dist/nodes/generated/giving/PlanningCenterGiving.node.d.ts +308 -0
- package/dist/nodes/generated/giving/PlanningCenterGiving.node.js +25566 -0
- package/dist/nodes/generated/giving/PlanningCenterGiving.node.js.map +1 -0
- package/dist/nodes/generated/giving/giving.svg +4 -0
- package/dist/nodes/generated/giving/pco.svg +4 -0
- package/dist/nodes/generated/groups/PlanningCenterGroups.node.d.ts +189 -0
- package/dist/nodes/generated/groups/PlanningCenterGroups.node.js +15344 -0
- package/dist/nodes/generated/groups/PlanningCenterGroups.node.js.map +1 -0
- package/dist/nodes/generated/groups/groups.svg +4 -0
- package/dist/nodes/generated/groups/pco.svg +4 -0
- package/dist/nodes/generated/people/PlanningCenterPeople.node.d.ts +979 -0
- package/dist/nodes/generated/people/PlanningCenterPeople.node.js +102040 -0
- package/dist/nodes/generated/people/PlanningCenterPeople.node.js.map +1 -0
- package/dist/nodes/generated/people/pco.svg +4 -0
- package/dist/nodes/generated/people/people.svg +4 -0
- package/dist/nodes/generated/publishing/PlanningCenterPublishing.node.d.ts +130 -0
- package/dist/nodes/generated/publishing/PlanningCenterPublishing.node.js +10671 -0
- package/dist/nodes/generated/publishing/PlanningCenterPublishing.node.js.map +1 -0
- package/dist/nodes/generated/publishing/pco.svg +4 -0
- package/dist/nodes/generated/publishing/publishing.svg +4 -0
- package/dist/nodes/generated/registrations/PlanningCenterRegistrations.node.d.ts +55 -0
- package/dist/nodes/generated/registrations/PlanningCenterRegistrations.node.js +3640 -0
- package/dist/nodes/generated/registrations/PlanningCenterRegistrations.node.js.map +1 -0
- package/dist/nodes/generated/registrations/pco.svg +4 -0
- package/dist/nodes/generated/registrations/registrations.svg +4 -0
- package/dist/nodes/generated/services/PlanningCenterServices.node.d.ts +1032 -0
- package/dist/nodes/generated/services/PlanningCenterServices.node.js +82196 -0
- package/dist/nodes/generated/services/PlanningCenterServices.node.js.map +1 -0
- package/dist/nodes/generated/services/pco.svg +4 -0
- package/dist/nodes/generated/services/services.svg +4 -0
- package/dist/nodes/generated/webhooks/PlanningCenterWebhooks.node.d.ts +25 -0
- package/dist/nodes/generated/webhooks/PlanningCenterWebhooks.node.js +1346 -0
- package/dist/nodes/generated/webhooks/PlanningCenterWebhooks.node.js.map +1 -0
- package/dist/nodes/generated/webhooks/pco.svg +4 -0
- package/dist/nodes/generated/webhooks/webhooks.svg +4 -0
- package/dist/src/generator/checkGenerated.d.ts +1 -0
- package/dist/src/generator/checkGenerated.js +34 -0
- package/dist/src/generator/checkGenerated.js.map +1 -0
- package/dist/src/generator/config.d.ts +13 -0
- package/dist/src/generator/config.js +114 -0
- package/dist/src/generator/config.js.map +1 -0
- package/dist/src/generator/generate.d.ts +1 -0
- package/dist/src/generator/generate.js +26 -0
- package/dist/src/generator/generate.js.map +1 -0
- package/dist/src/generator/labels.d.ts +3 -0
- package/dist/src/generator/labels.js +23 -0
- package/dist/src/generator/labels.js.map +1 -0
- package/dist/src/generator/model.d.ts +81 -0
- package/dist/src/generator/model.js +3 -0
- package/dist/src/generator/model.js.map +1 -0
- package/dist/src/generator/openapi.d.ts +3 -0
- package/dist/src/generator/openapi.js +667 -0
- package/dist/src/generator/openapi.js.map +1 -0
- package/dist/src/generator/refreshSnapshots.d.ts +1 -0
- package/dist/src/generator/refreshSnapshots.js +28 -0
- package/dist/src/generator/refreshSnapshots.js.map +1 -0
- package/dist/src/generator/render.d.ts +3 -0
- package/dist/src/generator/render.js +580 -0
- package/dist/src/generator/render.js.map +1 -0
- package/dist/src/runtime/execute.d.ts +2 -0
- package/dist/src/runtime/execute.js +25 -0
- package/dist/src/runtime/execute.js.map +1 -0
- package/dist/src/runtime/jsonApi.d.ts +3 -0
- package/dist/src/runtime/jsonApi.js +43 -0
- package/dist/src/runtime/jsonApi.js.map +1 -0
- package/dist/src/runtime/pagination.d.ts +8 -0
- package/dist/src/runtime/pagination.js +68 -0
- package/dist/src/runtime/pagination.js.map +1 -0
- package/dist/src/runtime/request.d.ts +22 -0
- package/dist/src/runtime/request.js +93 -0
- package/dist/src/runtime/request.js.map +1 -0
- package/dist/src/runtime/resourceLocator.d.ts +1 -0
- package/dist/src/runtime/resourceLocator.js +15 -0
- package/dist/src/runtime/resourceLocator.js.map +1 -0
- package/dist/tests/generator.test.d.ts +1 -0
- package/dist/tests/generator.test.js +622 -0
- package/dist/tests/generator.test.js.map +1 -0
- package/dist/tests/metadata.test.d.ts +1 -0
- package/dist/tests/metadata.test.js +124 -0
- package/dist/tests/metadata.test.js.map +1 -0
- package/dist/tests/runtime.test.d.ts +1 -0
- package/dist/tests/runtime.test.js +181 -0
- package/dist/tests/runtime.test.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const vitest_1 = require("vitest");
|
|
37
|
+
const entrypoint = __importStar(require("../index"));
|
|
38
|
+
const config_1 = require("../src/generator/config");
|
|
39
|
+
const openapi_1 = require("../src/generator/openapi");
|
|
40
|
+
const generatedNodeClasses = config_1.generatedProductConfigs.map((config) => entrypoint[config.className]);
|
|
41
|
+
function collectDisplayNames(value, labels = []) {
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
for (const item of value)
|
|
44
|
+
collectDisplayNames(item, labels);
|
|
45
|
+
return labels;
|
|
46
|
+
}
|
|
47
|
+
if (!value || typeof value !== 'object')
|
|
48
|
+
return labels;
|
|
49
|
+
const record = value;
|
|
50
|
+
if (typeof record.displayName === 'string')
|
|
51
|
+
labels.push(record.displayName);
|
|
52
|
+
for (const nestedValue of Object.values(record))
|
|
53
|
+
collectDisplayNames(nestedValue, labels);
|
|
54
|
+
return labels;
|
|
55
|
+
}
|
|
56
|
+
(0, vitest_1.describe)('generated Planning Center nodes', () => {
|
|
57
|
+
(0, vitest_1.it)('exposes required n8n descriptions for generated products', () => {
|
|
58
|
+
const nodes = generatedNodeClasses.map((NodeClass) => new NodeClass());
|
|
59
|
+
(0, vitest_1.expect)(nodes.map((node) => node.description.displayName)).toEqual(config_1.generatedProductConfigs.map((config) => config.displayName));
|
|
60
|
+
nodes.forEach((node, index) => {
|
|
61
|
+
const config = config_1.generatedProductConfigs[index];
|
|
62
|
+
(0, vitest_1.expect)(node.description.credentials).toEqual([{ name: 'planningCenterPatApi', required: true }]);
|
|
63
|
+
(0, vitest_1.expect)(node.description.icon).toBe(`file:${config.product}.svg`);
|
|
64
|
+
(0, vitest_1.expect)(node.description.properties.some((property) => property.name === 'resource')).toBe(true);
|
|
65
|
+
(0, vitest_1.expect)(node.description.properties.some((property) => property.name === 'operation')).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
(0, vitest_1.it)('records metadata summaries for generated products', async () => {
|
|
69
|
+
const summaries = await Promise.all(config_1.generatedProductConfigs.map(openapi_1.buildProductGeneration));
|
|
70
|
+
(0, vitest_1.expect)(summaries.map((summary) => summary.product).sort()).toEqual(config_1.generatedProductConfigs.map((config) => config.product).sort());
|
|
71
|
+
for (const summary of summaries) {
|
|
72
|
+
(0, vitest_1.expect)(summary.operationCount).toBeGreaterThan(0);
|
|
73
|
+
(0, vitest_1.expect)(summary.resourceCount).toBeGreaterThan(0);
|
|
74
|
+
(0, vitest_1.expect)(summary.exclusions).toEqual([]);
|
|
75
|
+
(0, vitest_1.expect)(summary.operations.some((operation) => operation.path.startsWith(`/${summary.product}/v2`))).toBe(true);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
(0, vitest_1.it)('defaults each generated resource to a read operation when one exists', async () => {
|
|
79
|
+
const summaries = await Promise.all(config_1.generatedProductConfigs.map(openapi_1.buildProductGeneration));
|
|
80
|
+
for (const summary of summaries) {
|
|
81
|
+
const operationsByResource = new Map();
|
|
82
|
+
for (const operation of summary.operations) {
|
|
83
|
+
operationsByResource.set(operation.resource, [...(operationsByResource.get(operation.resource) ?? []), operation]);
|
|
84
|
+
}
|
|
85
|
+
for (const [resource, operations] of operationsByResource) {
|
|
86
|
+
if (operations.some((operation) => operation.method === 'GET')) {
|
|
87
|
+
(0, vitest_1.expect)(operations[0].method, `${summary.product}:${resource}`).toBe('GET');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
(0, vitest_1.it)('does not treat singleton GET responses as paginated lists', async () => {
|
|
93
|
+
const currentConfig = config_1.generatedProductConfigs.find((config) => config.product === 'current');
|
|
94
|
+
(0, vitest_1.expect)(currentConfig).toBeDefined();
|
|
95
|
+
const summary = await (0, openapi_1.buildProductGeneration)(currentConfig);
|
|
96
|
+
const getMeOperation = summary.operations.find((operation) => operation.id === 'getMe');
|
|
97
|
+
const currentNode = new entrypoint.PlanningCenterCurrent();
|
|
98
|
+
const propertyNames = currentNode.description.properties.map((property) => property.name);
|
|
99
|
+
(0, vitest_1.expect)(getMeOperation).toMatchObject({
|
|
100
|
+
isList: false,
|
|
101
|
+
operation: 'Get Me',
|
|
102
|
+
path: '/current/v2/me',
|
|
103
|
+
});
|
|
104
|
+
(0, vitest_1.expect)(propertyNames).not.toContain('getMe_returnAll');
|
|
105
|
+
(0, vitest_1.expect)(propertyNames).not.toContain('getMe_limit');
|
|
106
|
+
});
|
|
107
|
+
(0, vitest_1.it)('derives friendly operation labels from HTTP method and path shape', async () => {
|
|
108
|
+
const peopleConfig = config_1.generatedProductConfigs.find((config) => config.product === 'people');
|
|
109
|
+
const givingConfig = config_1.generatedProductConfigs.find((config) => config.product === 'giving');
|
|
110
|
+
const servicesConfig = config_1.generatedProductConfigs.find((config) => config.product === 'services');
|
|
111
|
+
(0, vitest_1.expect)(peopleConfig).toBeDefined();
|
|
112
|
+
(0, vitest_1.expect)(givingConfig).toBeDefined();
|
|
113
|
+
(0, vitest_1.expect)(servicesConfig).toBeDefined();
|
|
114
|
+
const [peopleSummary, givingSummary, servicesSummary] = await Promise.all([
|
|
115
|
+
(0, openapi_1.buildProductGeneration)(peopleConfig),
|
|
116
|
+
(0, openapi_1.buildProductGeneration)(givingConfig),
|
|
117
|
+
(0, openapi_1.buildProductGeneration)(servicesConfig),
|
|
118
|
+
]);
|
|
119
|
+
const operations = Object.fromEntries(peopleSummary.operations.map((operation) => [operation.id, operation.operation]));
|
|
120
|
+
const givingOperations = Object.fromEntries(givingSummary.operations.map((operation) => [operation.id, operation.operation]));
|
|
121
|
+
const servicesOperations = Object.fromEntries(servicesSummary.operations.map((operation) => [operation.id, operation.operation]));
|
|
122
|
+
(0, vitest_1.expect)(operations.getFormsFormIdFormSubmissions).toBe('List Form Submissions (via Form)');
|
|
123
|
+
(0, vitest_1.expect)(operations.getFormsFormIdFormSubmissionsFormSubmissionId).toBe('Get Form Submission (via Form)');
|
|
124
|
+
(0, vitest_1.expect)(operations.postFormsFormIdFormSubmissions).toBe('Create Form Submission (via Form)');
|
|
125
|
+
(0, vitest_1.expect)(operations.patchFormsFormIdFormSubmissionsFormSubmissionIdPersonPersonId).toBe('Update Person (via Form Submission)');
|
|
126
|
+
(0, vitest_1.expect)(operations.deleteFormsFormIdFormSubmissionsFormSubmissionIdPersonPersonId).toBe('Delete Person (via Form Submission)');
|
|
127
|
+
(0, vitest_1.expect)(operations.getFormsFormIdFormSubmissionsFormSubmissionIdFormSubmissionValues).toBe('List Form Submission Values (via Form Submission)');
|
|
128
|
+
(0, vitest_1.expect)(operations.getFormsFormIdFormSubmissionsFormSubmissionIdFormSubmissionValuesFormSubmissionValueId).toBe('Get Form Submission Value (via Form Submission)');
|
|
129
|
+
(0, vitest_1.expect)(operations.getPeople).toBe('List People');
|
|
130
|
+
(0, vitest_1.expect)(operations.getHouseholdsHouseholdIdPeople).toBe('List People (via Household)');
|
|
131
|
+
(0, vitest_1.expect)(operations.getListsListIdPeople).toBe('List People (via List)');
|
|
132
|
+
(0, vitest_1.expect)(operations.getPeoplePersonId).toBe('Get Person');
|
|
133
|
+
(0, vitest_1.expect)(operations.getPeoplePersonIdWorkflowCardsWorkflowCardIdPersonPersonId).toBe('Get Person (via Workflow Card)');
|
|
134
|
+
(0, vitest_1.expect)(operations.getMaritalStatusesMaritalStatusId).toBe('Get Marital Status');
|
|
135
|
+
(0, vitest_1.expect)(givingOperations.getCampusesCampusId).toBe('Get Campus');
|
|
136
|
+
(0, vitest_1.expect)(servicesOperations.getFoldersFolderIdFoldersFolderId).toBe('Get Folder (via Folder)');
|
|
137
|
+
});
|
|
138
|
+
(0, vitest_1.it)('renders selected operation subtitles from endpoint descriptions while preserving operation IDs', () => {
|
|
139
|
+
const node = new entrypoint.PlanningCenterPeople();
|
|
140
|
+
const operationProperty = node.description.properties.find((property) => property.name === 'operation' && property.options?.some((option) => option.value === 'getPeople'));
|
|
141
|
+
(0, vitest_1.expect)(node.description.subtitle).not.toBe('={{$parameter["operation"]}}');
|
|
142
|
+
(0, vitest_1.expect)(node.description.subtitle).toContain('$parameter["operation"]');
|
|
143
|
+
(0, vitest_1.expect)(node.description.subtitle).toContain('"getPeople":"GET /people"');
|
|
144
|
+
(0, vitest_1.expect)(operationProperty?.options).toEqual(vitest_1.expect.arrayContaining([
|
|
145
|
+
vitest_1.expect.objectContaining({
|
|
146
|
+
name: 'List People',
|
|
147
|
+
value: 'getPeople',
|
|
148
|
+
description: 'GET /people',
|
|
149
|
+
}),
|
|
150
|
+
]));
|
|
151
|
+
});
|
|
152
|
+
(0, vitest_1.it)('does not emit duplicate operation labels within a product', async () => {
|
|
153
|
+
const summaries = await Promise.all(config_1.productConfigs.map(openapi_1.buildProductGeneration));
|
|
154
|
+
for (const summary of summaries) {
|
|
155
|
+
const operationsByLabel = new Map();
|
|
156
|
+
for (const operation of summary.operations) {
|
|
157
|
+
operationsByLabel.set(operation.operation, [
|
|
158
|
+
...(operationsByLabel.get(operation.operation) ?? []),
|
|
159
|
+
`${operation.method} ${operation.path}`,
|
|
160
|
+
]);
|
|
161
|
+
}
|
|
162
|
+
const duplicateLabels = [...operationsByLabel.entries()]
|
|
163
|
+
.filter(([, paths]) => paths.length > 1)
|
|
164
|
+
.map(([label, paths]) => `${label}: ${paths.join(', ')}`);
|
|
165
|
+
(0, vitest_1.expect)(duplicateLabels, summary.product).toEqual([]);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
(0, vitest_1.it)('renders only useful query filters for form submission lists', async () => {
|
|
169
|
+
const peopleConfig = config_1.generatedProductConfigs.find((config) => config.product === 'people');
|
|
170
|
+
(0, vitest_1.expect)(peopleConfig).toBeDefined();
|
|
171
|
+
const summary = await (0, openapi_1.buildProductGeneration)(peopleConfig);
|
|
172
|
+
const operation = summary.operations.find((candidate) => candidate.id === 'getFormsFormIdFormSubmissions');
|
|
173
|
+
(0, vitest_1.expect)(operation).toBeDefined();
|
|
174
|
+
const queryParameters = operation.queryParameters.map((parameter) => parameter.sourceName);
|
|
175
|
+
(0, vitest_1.expect)(queryParameters).toContain('where[created_at]');
|
|
176
|
+
(0, vitest_1.expect)(queryParameters).toContain('where[created_at][gte]');
|
|
177
|
+
(0, vitest_1.expect)(queryParameters).toContain('where[updated_at][lte]');
|
|
178
|
+
(0, vitest_1.expect)(queryParameters).toContain('where[submitter_name]');
|
|
179
|
+
(0, vitest_1.expect)(queryParameters).toContain('where[person][id]');
|
|
180
|
+
(0, vitest_1.expect)(queryParameters).toContain('include');
|
|
181
|
+
(0, vitest_1.expect)(queryParameters).toContain('order');
|
|
182
|
+
(0, vitest_1.expect)(queryParameters).not.toContain('where[form][id]');
|
|
183
|
+
(0, vitest_1.expect)(queryParameters).not.toContain('where[person][addresses][city]');
|
|
184
|
+
(0, vitest_1.expect)(queryParameters).not.toContain('where[form][campus][updated_at]');
|
|
185
|
+
(0, vitest_1.expect)(queryParameters).not.toContain('fields[FormSubmission]');
|
|
186
|
+
(0, vitest_1.expect)(queryParameters).not.toContain('per_page');
|
|
187
|
+
(0, vitest_1.expect)(queryParameters).not.toContain('offset');
|
|
188
|
+
(0, vitest_1.expect)(queryParameters.length).toBeLessThan(20);
|
|
189
|
+
const queryOptions = Object.fromEntries(operation.queryOptions.map((option) => [option.name, option]));
|
|
190
|
+
(0, vitest_1.expect)(queryOptions.wherecreatedAtFilter).toMatchObject({
|
|
191
|
+
displayName: 'Created At',
|
|
192
|
+
group: 'filter',
|
|
193
|
+
kind: 'operator',
|
|
194
|
+
});
|
|
195
|
+
(0, vitest_1.expect)(queryOptions.wherecreatedAtFilter.operators).toEqual([
|
|
196
|
+
{ name: 'Equals', value: 'eq', sourceName: 'where[created_at]' },
|
|
197
|
+
{ name: 'Greater Than', value: 'gt', sourceName: 'where[created_at][gt]' },
|
|
198
|
+
{ name: 'Greater Than Or Equal', value: 'gte', sourceName: 'where[created_at][gte]' },
|
|
199
|
+
{ name: 'Less Than', value: 'lt', sourceName: 'where[created_at][lt]' },
|
|
200
|
+
{ name: 'Less Than Or Equal', value: 'lte', sourceName: 'where[created_at][lte]' },
|
|
201
|
+
]);
|
|
202
|
+
(0, vitest_1.expect)(queryOptions.wherepersonid).toMatchObject({
|
|
203
|
+
displayName: 'Person ID',
|
|
204
|
+
group: 'filter',
|
|
205
|
+
kind: 'single',
|
|
206
|
+
sourceName: 'where[person][id]',
|
|
207
|
+
});
|
|
208
|
+
(0, vitest_1.expect)(queryOptions.include).toMatchObject({
|
|
209
|
+
displayName: 'Include',
|
|
210
|
+
group: 'include',
|
|
211
|
+
kind: 'single',
|
|
212
|
+
sourceName: 'include',
|
|
213
|
+
});
|
|
214
|
+
(0, vitest_1.expect)(queryOptions.order).toMatchObject({
|
|
215
|
+
displayName: 'Order',
|
|
216
|
+
group: 'order',
|
|
217
|
+
kind: 'single',
|
|
218
|
+
sourceName: 'order',
|
|
219
|
+
valueOptions: vitest_1.expect.arrayContaining([
|
|
220
|
+
{ name: 'Created At Ascending', value: 'created_at' },
|
|
221
|
+
{ name: 'Created At Descending', value: '-created_at' },
|
|
222
|
+
]),
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
(0, vitest_1.it)('renders grouped query options as multi-value fixed collections', () => {
|
|
226
|
+
const node = new entrypoint.PlanningCenterPeople();
|
|
227
|
+
const filterProperty = node.description.properties.find((property) => property.name === 'getFormsFormIdFormSubmissions_filter');
|
|
228
|
+
const orderProperty = node.description.properties.find((property) => property.name === 'getFormsFormIdFormSubmissions_order');
|
|
229
|
+
const includeProperty = node.description.properties.find((property) => property.name === 'getFormsFormIdFormSubmissions_include');
|
|
230
|
+
(0, vitest_1.expect)(filterProperty).toMatchObject({
|
|
231
|
+
displayName: 'Filter',
|
|
232
|
+
placeholder: 'Filter by',
|
|
233
|
+
typeOptions: { multipleValues: true },
|
|
234
|
+
});
|
|
235
|
+
(0, vitest_1.expect)(orderProperty).toMatchObject({
|
|
236
|
+
displayName: 'Order',
|
|
237
|
+
placeholder: 'Order by',
|
|
238
|
+
typeOptions: { multipleValues: true },
|
|
239
|
+
});
|
|
240
|
+
(0, vitest_1.expect)(includeProperty).toMatchObject({
|
|
241
|
+
displayName: 'Include',
|
|
242
|
+
placeholder: 'Include data',
|
|
243
|
+
typeOptions: { multipleValues: true },
|
|
244
|
+
});
|
|
245
|
+
const orderOption = orderProperty.options.find((option) => option.name === 'order');
|
|
246
|
+
const orderValue = orderOption.values.find((value) => value.name === 'value');
|
|
247
|
+
(0, vitest_1.expect)(orderValue).toMatchObject({
|
|
248
|
+
displayName: 'Value',
|
|
249
|
+
name: 'value',
|
|
250
|
+
type: 'options',
|
|
251
|
+
options: vitest_1.expect.arrayContaining([
|
|
252
|
+
{ name: 'Created At Ascending', value: 'created_at' },
|
|
253
|
+
{ name: 'Created At Descending', value: '-created_at' },
|
|
254
|
+
]),
|
|
255
|
+
default: '',
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
(0, vitest_1.it)('renders lookup-enabled fields as searchable resource locators with manual ID mode', () => {
|
|
259
|
+
const node = new entrypoint.PlanningCenterGroups();
|
|
260
|
+
const groupTypeProperty = node.description.properties.find((property) => property.name === 'getGroupTypesGroupTypeIdGroups_groupTypeId');
|
|
261
|
+
(0, vitest_1.expect)(groupTypeProperty).toMatchObject({
|
|
262
|
+
displayName: 'Group Type ID',
|
|
263
|
+
type: 'resourceLocator',
|
|
264
|
+
default: { mode: 'list', value: '' },
|
|
265
|
+
modes: [
|
|
266
|
+
vitest_1.expect.objectContaining({
|
|
267
|
+
displayName: 'List',
|
|
268
|
+
name: 'list',
|
|
269
|
+
type: 'list',
|
|
270
|
+
typeOptions: vitest_1.expect.objectContaining({ searchable: true, searchListMethod: vitest_1.expect.any(String) }),
|
|
271
|
+
}),
|
|
272
|
+
vitest_1.expect.objectContaining({ displayName: 'ID', name: 'id', type: 'string' }),
|
|
273
|
+
],
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
(0, vitest_1.it)('infers lookup metadata for supported single-ID fields and defers multi-ID fields', async () => {
|
|
277
|
+
const groupsConfig = config_1.generatedProductConfigs.find((config) => config.product === 'groups');
|
|
278
|
+
(0, vitest_1.expect)(groupsConfig).toBeDefined();
|
|
279
|
+
const summary = await (0, openapi_1.buildProductGeneration)(groupsConfig);
|
|
280
|
+
const operations = Object.fromEntries(summary.operations.map((operation) => [operation.id, operation]));
|
|
281
|
+
const groupTypeGroups = operations.getGroupTypesGroupTypeIdGroups;
|
|
282
|
+
const campusGroups = operations.getCampusesCampusIdGroups;
|
|
283
|
+
const campusGroupPatch = operations.patchCampusesCampusIdGroupsGroupId;
|
|
284
|
+
(0, vitest_1.expect)(groupTypeGroups.pathParameters.find((field) => field.sourceName === 'group_type_id')?.lookup).toMatchObject({
|
|
285
|
+
sourcePath: '/groups/v2/group_types',
|
|
286
|
+
parentBindings: [],
|
|
287
|
+
resultLimit: 25,
|
|
288
|
+
});
|
|
289
|
+
(0, vitest_1.expect)(operations.getCampuses.queryOptions.find((option) => option.sourceName === 'where[id]')?.lookup).toMatchObject({
|
|
290
|
+
sourcePath: '/groups/v2/campuses',
|
|
291
|
+
searchFilter: 'where[name]',
|
|
292
|
+
});
|
|
293
|
+
(0, vitest_1.expect)(campusGroups.queryOptions.find((option) => option.sourceName === 'where[group_type][id]')?.lookup).toMatchObject({
|
|
294
|
+
sourcePath: '/groups/v2/group_types',
|
|
295
|
+
});
|
|
296
|
+
(0, vitest_1.expect)(campusGroupPatch.attributeFields.find((field) => field.sourceName === 'group_type_id')?.lookup).toBeDefined();
|
|
297
|
+
(0, vitest_1.expect)(campusGroupPatch.relationshipFields.find((field) => field.relationshipName === 'group_type')?.lookup).toBeDefined();
|
|
298
|
+
(0, vitest_1.expect)(campusGroupPatch.attributeFields.find((field) => field.sourceName === 'tag_ids')?.lookup).toBeUndefined();
|
|
299
|
+
(0, vitest_1.expect)(summary.operations.flatMap((operation) => operation.relationshipFields).filter((field) => field.multiple && field.lookup)).toEqual([]);
|
|
300
|
+
});
|
|
301
|
+
(0, vitest_1.it)('infers split-name lookup metadata for Giving people without a combined search filter', async () => {
|
|
302
|
+
const givingConfig = config_1.generatedProductConfigs.find((config) => config.product === 'giving');
|
|
303
|
+
(0, vitest_1.expect)(givingConfig).toBeDefined();
|
|
304
|
+
const summary = await (0, openapi_1.buildProductGeneration)(givingConfig);
|
|
305
|
+
const operation = summary.operations.find((candidate) => candidate.id === 'getPeoplePersonIdDonations');
|
|
306
|
+
const lookup = operation?.pathParameters.find((field) => field.sourceName === 'person_id')?.lookup;
|
|
307
|
+
(0, vitest_1.expect)(operation?.operation).toBe('List Donations (via Person)');
|
|
308
|
+
(0, vitest_1.expect)(lookup).toMatchObject({
|
|
309
|
+
sourcePath: '/giving/v2/people',
|
|
310
|
+
searchFilter: undefined,
|
|
311
|
+
splitNameSearch: {
|
|
312
|
+
firstNameFilter: 'where[first_name]',
|
|
313
|
+
lastNameFilter: 'where[last_name]',
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
(0, vitest_1.expect)(lookup?.labelFields).toEqual([
|
|
317
|
+
'name',
|
|
318
|
+
'full_name',
|
|
319
|
+
'display_name',
|
|
320
|
+
'search_name',
|
|
321
|
+
'path_name',
|
|
322
|
+
'first_name last_name',
|
|
323
|
+
'given_name last_name',
|
|
324
|
+
'nickname last_name',
|
|
325
|
+
'title',
|
|
326
|
+
'subject',
|
|
327
|
+
'label',
|
|
328
|
+
]);
|
|
329
|
+
});
|
|
330
|
+
(0, vitest_1.it)('uses generated list-search methods with limits, search filters, labels, and parent bindings', async () => {
|
|
331
|
+
const node = new entrypoint.PlanningCenterGroups();
|
|
332
|
+
const httpRequest = vitest_1.vi.fn().mockResolvedValue({
|
|
333
|
+
data: [
|
|
334
|
+
{ id: '1', type: 'Campus', attributes: { name: 'North' } },
|
|
335
|
+
{ id: '2', type: 'Campus', attributes: { title: 'Fallback Title' } },
|
|
336
|
+
],
|
|
337
|
+
});
|
|
338
|
+
const context = {
|
|
339
|
+
getCredentials: vitest_1.vi.fn().mockResolvedValue({
|
|
340
|
+
applicationId: 'app-id',
|
|
341
|
+
secret: 'secret',
|
|
342
|
+
baseUrl: 'https://api.example.test',
|
|
343
|
+
}),
|
|
344
|
+
getNode: () => ({ name: 'Planning Center Groups', type: 'planningCenterGroups' }),
|
|
345
|
+
getNodeParameter: vitest_1.vi.fn((name, fallback) => {
|
|
346
|
+
if (name === 'getCampusesCampusIdGroupsGroupId_campusId')
|
|
347
|
+
return { __rl: true, mode: 'list', value: '12' };
|
|
348
|
+
return fallback;
|
|
349
|
+
}),
|
|
350
|
+
helpers: { httpRequest },
|
|
351
|
+
};
|
|
352
|
+
await (0, vitest_1.expect)(node.methods.listSearch.searchGetCampusesCampusIdGroupsGroupIdGroupId.call(context, 'small')).resolves.toEqual({
|
|
353
|
+
results: [
|
|
354
|
+
{ name: 'North (1)', value: '1' },
|
|
355
|
+
{ name: 'Fallback Title (2)', value: '2' },
|
|
356
|
+
],
|
|
357
|
+
});
|
|
358
|
+
(0, vitest_1.expect)(httpRequest).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
|
|
359
|
+
url: 'https://api.example.test/groups/v2/campuses/12/groups',
|
|
360
|
+
qs: { per_page: 25, 'where[name]': 'small' },
|
|
361
|
+
}));
|
|
362
|
+
context.getNodeParameter = vitest_1.vi.fn((_name, fallback) => fallback);
|
|
363
|
+
httpRequest.mockClear();
|
|
364
|
+
await (0, vitest_1.expect)(node.methods.listSearch.searchGetCampusesCampusIdGroupsGroupIdGroupId.call(context, 'small')).resolves.toEqual({
|
|
365
|
+
results: [],
|
|
366
|
+
});
|
|
367
|
+
(0, vitest_1.expect)(httpRequest).not.toHaveBeenCalled();
|
|
368
|
+
});
|
|
369
|
+
(0, vitest_1.it)('uses bounded split-name lookup search for Giving person locators', async () => {
|
|
370
|
+
const node = new entrypoint.PlanningCenterGiving();
|
|
371
|
+
const firstNamePeople = Array.from({ length: 24 }, (_, index) => ({
|
|
372
|
+
id: String(index + 1),
|
|
373
|
+
type: 'Person',
|
|
374
|
+
attributes: { first_name: `First${index + 1}`, last_name: 'Match' },
|
|
375
|
+
}));
|
|
376
|
+
const httpRequest = vitest_1.vi.fn((request) => {
|
|
377
|
+
if (request.qs?.['where[first_name]']) {
|
|
378
|
+
return Promise.resolve({ data: firstNamePeople });
|
|
379
|
+
}
|
|
380
|
+
if (request.qs?.['where[last_name]']) {
|
|
381
|
+
return Promise.resolve({
|
|
382
|
+
data: [
|
|
383
|
+
{ id: '2', type: 'Person', attributes: { first_name: 'Duplicate', last_name: 'Match' } },
|
|
384
|
+
{ id: '25', type: 'Person', attributes: { first_name: 'Last25', last_name: 'Match' } },
|
|
385
|
+
{ id: '26', type: 'Person', attributes: { first_name: 'Last26', last_name: 'Match' } },
|
|
386
|
+
],
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
return Promise.resolve({ data: [] });
|
|
390
|
+
});
|
|
391
|
+
const context = {
|
|
392
|
+
getCredentials: vitest_1.vi.fn().mockResolvedValue({
|
|
393
|
+
applicationId: 'app-id',
|
|
394
|
+
secret: 'secret',
|
|
395
|
+
baseUrl: 'https://api.example.test',
|
|
396
|
+
}),
|
|
397
|
+
getNode: () => ({ name: 'Planning Center Giving', type: 'planningCenterGiving' }),
|
|
398
|
+
getNodeParameter: vitest_1.vi.fn((_name, fallback) => fallback),
|
|
399
|
+
helpers: { httpRequest },
|
|
400
|
+
};
|
|
401
|
+
await (0, vitest_1.expect)(node.methods.listSearch.searchGetPeoplePersonIdDonationsPersonId.call(context, 'Ada Lovelace')).resolves.toEqual({
|
|
402
|
+
results: [
|
|
403
|
+
...firstNamePeople.map((person) => ({ name: `${person.attributes.first_name} ${person.attributes.last_name} (${person.id})`, value: person.id })),
|
|
404
|
+
{ name: 'Last25 Match (25)', value: '25' },
|
|
405
|
+
],
|
|
406
|
+
});
|
|
407
|
+
(0, vitest_1.expect)(httpRequest).toHaveBeenCalledTimes(2);
|
|
408
|
+
(0, vitest_1.expect)(httpRequest).toHaveBeenNthCalledWith(1, vitest_1.expect.objectContaining({
|
|
409
|
+
url: 'https://api.example.test/giving/v2/people',
|
|
410
|
+
qs: { per_page: 25, 'where[first_name]': 'Ada' },
|
|
411
|
+
}));
|
|
412
|
+
(0, vitest_1.expect)(httpRequest).toHaveBeenNthCalledWith(2, vitest_1.expect.objectContaining({
|
|
413
|
+
url: 'https://api.example.test/giving/v2/people',
|
|
414
|
+
qs: { per_page: 25, 'where[last_name]': 'Lovelace' },
|
|
415
|
+
}));
|
|
416
|
+
httpRequest.mockClear();
|
|
417
|
+
await node.methods.listSearch.searchGetPeoplePersonIdDonationsPersonId.call(context, 'Ada');
|
|
418
|
+
(0, vitest_1.expect)(httpRequest).toHaveBeenCalledTimes(2);
|
|
419
|
+
(0, vitest_1.expect)(httpRequest).toHaveBeenNthCalledWith(1, vitest_1.expect.objectContaining({ qs: { per_page: 25, 'where[first_name]': 'Ada' } }));
|
|
420
|
+
(0, vitest_1.expect)(httpRequest).toHaveBeenNthCalledWith(2, vitest_1.expect.objectContaining({ qs: { per_page: 25, 'where[last_name]': 'Ada' } }));
|
|
421
|
+
});
|
|
422
|
+
(0, vitest_1.it)('uses one unfiltered request for initial Giving person locator results', async () => {
|
|
423
|
+
const node = new entrypoint.PlanningCenterGiving();
|
|
424
|
+
const httpRequest = vitest_1.vi.fn().mockResolvedValue({
|
|
425
|
+
data: [{ id: '1', type: 'Person', attributes: { first_name: 'Ada', last_name: 'Lovelace' } }],
|
|
426
|
+
});
|
|
427
|
+
const context = {
|
|
428
|
+
getCredentials: vitest_1.vi.fn().mockResolvedValue({
|
|
429
|
+
applicationId: 'app-id',
|
|
430
|
+
secret: 'secret',
|
|
431
|
+
baseUrl: 'https://api.example.test',
|
|
432
|
+
}),
|
|
433
|
+
getNode: () => ({ name: 'Planning Center Giving', type: 'planningCenterGiving' }),
|
|
434
|
+
getNodeParameter: vitest_1.vi.fn((_name, fallback) => fallback),
|
|
435
|
+
helpers: { httpRequest },
|
|
436
|
+
};
|
|
437
|
+
await (0, vitest_1.expect)(node.methods.listSearch.searchGetPeoplePersonIdDonationsPersonId.call(context, '')).resolves.toEqual({
|
|
438
|
+
results: [{ name: 'Ada Lovelace (1)', value: '1' }],
|
|
439
|
+
});
|
|
440
|
+
(0, vitest_1.expect)(httpRequest).toHaveBeenCalledTimes(1);
|
|
441
|
+
(0, vitest_1.expect)(httpRequest).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
|
|
442
|
+
url: 'https://api.example.test/giving/v2/people',
|
|
443
|
+
qs: { per_page: 25 },
|
|
444
|
+
}));
|
|
445
|
+
});
|
|
446
|
+
(0, vitest_1.it)('executes lookup-enabled path, query, attribute, and relationship fields as IDs', async () => {
|
|
447
|
+
const node = new entrypoint.PlanningCenterGroups();
|
|
448
|
+
const httpRequest = vitest_1.vi.fn().mockResolvedValue({ data: { id: '34', type: 'Group' } });
|
|
449
|
+
const context = {
|
|
450
|
+
continueOnFail: () => false,
|
|
451
|
+
getCredentials: vitest_1.vi.fn().mockResolvedValue({
|
|
452
|
+
applicationId: 'app-id',
|
|
453
|
+
secret: 'secret',
|
|
454
|
+
baseUrl: 'https://api.example.test',
|
|
455
|
+
}),
|
|
456
|
+
getInputData: () => [{ json: {} }],
|
|
457
|
+
getNode: () => ({ name: 'Planning Center Groups', type: 'planningCenterGroups' }),
|
|
458
|
+
getNodeParameter: vitest_1.vi.fn((name, _itemIndex, fallback) => {
|
|
459
|
+
if (name === 'resource')
|
|
460
|
+
return 'Campus';
|
|
461
|
+
if (name === 'operation')
|
|
462
|
+
return 'patchCampusesCampusIdGroupsGroupId';
|
|
463
|
+
if (name === 'patchCampusesCampusIdGroupsGroupId_campusId')
|
|
464
|
+
return { __rl: true, mode: 'list', value: '12' };
|
|
465
|
+
if (name === 'patchCampusesCampusIdGroupsGroupId_groupId')
|
|
466
|
+
return { __rl: true, mode: 'id', value: '34' };
|
|
467
|
+
if (name === 'patchCampusesCampusIdGroupsGroupId_include')
|
|
468
|
+
return { include: [{ value: 'group_type' }] };
|
|
469
|
+
if (name === 'bodyMode')
|
|
470
|
+
return 'fields';
|
|
471
|
+
if (name === 'patchCampusesCampusIdGroupsGroupId_groupTypeId')
|
|
472
|
+
return { __rl: true, mode: 'list', value: '56' };
|
|
473
|
+
if (name === 'patchCampusesCampusIdGroupsGroupId_groupTypeIds')
|
|
474
|
+
return { __rl: true, mode: 'list', value: '78' };
|
|
475
|
+
if (name === 'additionalQueryParameters')
|
|
476
|
+
return fallback;
|
|
477
|
+
return fallback;
|
|
478
|
+
}),
|
|
479
|
+
helpers: { httpRequest },
|
|
480
|
+
};
|
|
481
|
+
await (0, vitest_1.expect)(node.execute.call(context)).resolves.toEqual([[vitest_1.expect.objectContaining({ json: vitest_1.expect.any(Object) })]]);
|
|
482
|
+
(0, vitest_1.expect)(httpRequest).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
|
|
483
|
+
method: 'PATCH',
|
|
484
|
+
url: 'https://api.example.test/groups/v2/campuses/12/groups/34',
|
|
485
|
+
qs: { include: 'group_type' },
|
|
486
|
+
body: {
|
|
487
|
+
data: {
|
|
488
|
+
type: 'Campus',
|
|
489
|
+
attributes: { group_type_id: '56' },
|
|
490
|
+
relationships: { group_type: { data: { type: 'GroupType', id: '78' } } },
|
|
491
|
+
},
|
|
492
|
+
},
|
|
493
|
+
}));
|
|
494
|
+
});
|
|
495
|
+
(0, vitest_1.it)('labels assignable attributes and relationships explicitly in body fields', () => {
|
|
496
|
+
const node = new entrypoint.PlanningCenterPeople();
|
|
497
|
+
const labelsByName = Object.fromEntries(node.description.properties
|
|
498
|
+
.filter((property) => String(property.name).startsWith('patchFieldDataFieldDatumId_fieldDefinition'))
|
|
499
|
+
.map((property) => [property.name, property.displayName]));
|
|
500
|
+
(0, vitest_1.expect)(labelsByName).toMatchObject({
|
|
501
|
+
patchFieldDataFieldDatumId_fieldDefinitionId: 'Attribute: Field Definition ID',
|
|
502
|
+
patchFieldDataFieldDatumId_fieldDefinitionIds: 'Relationship: Field Definition ID',
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
(0, vitest_1.it)('normalizes identifier acronym capitalization across generated labels', async () => {
|
|
506
|
+
const summaries = await Promise.all(config_1.generatedProductConfigs.map(openapi_1.buildProductGeneration));
|
|
507
|
+
const mixedCaseIdentifierToken = /\bId(?:s)?\b/;
|
|
508
|
+
const summaryLabels = summaries.flatMap((summary) => summary.operations.flatMap((operation) => [
|
|
509
|
+
...operation.pathParameters.map((field) => `${summary.product}:${operation.id}:path:${field.displayName}`),
|
|
510
|
+
...operation.queryParameters.map((field) => `${summary.product}:${operation.id}:query:${field.displayName}`),
|
|
511
|
+
...operation.attributeFields.map((field) => `${summary.product}:${operation.id}:attribute:${field.displayName}`),
|
|
512
|
+
...operation.relationshipFields.map((field) => `${summary.product}:${operation.id}:relationship:${field.displayName}`),
|
|
513
|
+
...operation.queryOptions.map((option) => `${summary.product}:${operation.id}:option:${option.displayName}`),
|
|
514
|
+
...operation.queryOptions.flatMap((option) => (option.valueOptions ?? []).map((valueOption) => `${summary.product}:${operation.id}:value-option:${valueOption.name}`)),
|
|
515
|
+
]));
|
|
516
|
+
const nodeLabels = generatedNodeClasses
|
|
517
|
+
.map((NodeClass) => new NodeClass())
|
|
518
|
+
.flatMap((node) => collectDisplayNames(node.description.properties).map((label) => `${node.description.name}:${label}`));
|
|
519
|
+
const mixedCaseLabels = [...summaryLabels, ...nodeLabels].filter((entry) => mixedCaseIdentifierToken.test(entry));
|
|
520
|
+
(0, vitest_1.expect)(mixedCaseLabels).toEqual([]);
|
|
521
|
+
});
|
|
522
|
+
(0, vitest_1.it)('executes form submission list when optional numeric query filters are unset', async () => {
|
|
523
|
+
const node = new entrypoint.PlanningCenterPeople();
|
|
524
|
+
const httpRequest = vitest_1.vi.fn().mockResolvedValue({ data: [] });
|
|
525
|
+
const missingNumberParameter = 'getFormsFormIdFormSubmissions_wherepersongrade';
|
|
526
|
+
const context = {
|
|
527
|
+
continueOnFail: () => false,
|
|
528
|
+
getCredentials: vitest_1.vi.fn().mockResolvedValue({
|
|
529
|
+
applicationId: 'app-id',
|
|
530
|
+
secret: 'secret',
|
|
531
|
+
baseUrl: 'https://api.example.test',
|
|
532
|
+
}),
|
|
533
|
+
getInputData: () => [{ json: {} }],
|
|
534
|
+
getNode: () => ({ name: 'Planning Center People', type: 'planningCenterPeople' }),
|
|
535
|
+
getNodeParameter: vitest_1.vi.fn((name, _itemIndex, fallback) => {
|
|
536
|
+
if (name === 'resource')
|
|
537
|
+
return 'Form';
|
|
538
|
+
if (name === 'operation')
|
|
539
|
+
return 'getFormsFormIdFormSubmissions';
|
|
540
|
+
if (name === 'getFormsFormIdFormSubmissions_formId')
|
|
541
|
+
return '123';
|
|
542
|
+
if (name === 'getFormsFormIdFormSubmissions_filter')
|
|
543
|
+
return fallback;
|
|
544
|
+
if (name === 'getFormsFormIdFormSubmissions_order')
|
|
545
|
+
return fallback;
|
|
546
|
+
if (name === 'getFormsFormIdFormSubmissions_include')
|
|
547
|
+
return fallback;
|
|
548
|
+
if (name === 'additionalQueryParameters')
|
|
549
|
+
return fallback;
|
|
550
|
+
if (name === 'getFormsFormIdFormSubmissions_returnAll')
|
|
551
|
+
return false;
|
|
552
|
+
if (name === 'getFormsFormIdFormSubmissions_limit')
|
|
553
|
+
return 1;
|
|
554
|
+
if (name === missingNumberParameter && fallback === undefined) {
|
|
555
|
+
throw new Error(`Could not get parameter "${missingNumberParameter}"`);
|
|
556
|
+
}
|
|
557
|
+
return fallback;
|
|
558
|
+
}),
|
|
559
|
+
helpers: { httpRequest },
|
|
560
|
+
};
|
|
561
|
+
await (0, vitest_1.expect)(node.execute.call(context)).resolves.toEqual([[]]);
|
|
562
|
+
(0, vitest_1.expect)(httpRequest).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
|
|
563
|
+
url: 'https://api.example.test/people/v2/forms/123/form_submissions',
|
|
564
|
+
qs: { per_page: 1 },
|
|
565
|
+
}));
|
|
566
|
+
});
|
|
567
|
+
(0, vitest_1.it)('maps selected query options to Planning Center query parameters', async () => {
|
|
568
|
+
const node = new entrypoint.PlanningCenterPeople();
|
|
569
|
+
const httpRequest = vitest_1.vi.fn().mockResolvedValue({ data: [] });
|
|
570
|
+
const context = {
|
|
571
|
+
continueOnFail: () => false,
|
|
572
|
+
getCredentials: vitest_1.vi.fn().mockResolvedValue({
|
|
573
|
+
applicationId: 'app-id',
|
|
574
|
+
secret: 'secret',
|
|
575
|
+
baseUrl: 'https://api.example.test',
|
|
576
|
+
}),
|
|
577
|
+
getInputData: () => [{ json: {} }],
|
|
578
|
+
getNode: () => ({ name: 'Planning Center People', type: 'planningCenterPeople' }),
|
|
579
|
+
getNodeParameter: vitest_1.vi.fn((name, _itemIndex, fallback) => {
|
|
580
|
+
if (name === 'resource')
|
|
581
|
+
return 'Form';
|
|
582
|
+
if (name === 'operation')
|
|
583
|
+
return 'getFormsFormIdFormSubmissions';
|
|
584
|
+
if (name === 'getFormsFormIdFormSubmissions_formId')
|
|
585
|
+
return '123';
|
|
586
|
+
if (name === 'getFormsFormIdFormSubmissions_filter') {
|
|
587
|
+
return {
|
|
588
|
+
wherecreatedAtFilter: [
|
|
589
|
+
{ operator: 'gte', value: '2026-01-01T00:00:00Z' },
|
|
590
|
+
{ operator: 'lte', value: '2026-01-31T23:59:59Z' },
|
|
591
|
+
],
|
|
592
|
+
wherepersonid: [{ value: '456' }],
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
if (name === 'getFormsFormIdFormSubmissions_order')
|
|
596
|
+
return { order: [{ value: '-created_at' }] };
|
|
597
|
+
if (name === 'getFormsFormIdFormSubmissions_include')
|
|
598
|
+
return { include: [{ value: 'person' }] };
|
|
599
|
+
if (name === 'additionalQueryParameters')
|
|
600
|
+
return fallback;
|
|
601
|
+
if (name === 'getFormsFormIdFormSubmissions_returnAll')
|
|
602
|
+
return false;
|
|
603
|
+
if (name === 'getFormsFormIdFormSubmissions_limit')
|
|
604
|
+
return 1;
|
|
605
|
+
return fallback;
|
|
606
|
+
}),
|
|
607
|
+
helpers: { httpRequest },
|
|
608
|
+
};
|
|
609
|
+
await (0, vitest_1.expect)(node.execute.call(context)).resolves.toEqual([[]]);
|
|
610
|
+
(0, vitest_1.expect)(httpRequest).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
|
|
611
|
+
qs: {
|
|
612
|
+
per_page: 1,
|
|
613
|
+
'where[created_at][gte]': '2026-01-01T00:00:00Z',
|
|
614
|
+
'where[created_at][lte]': '2026-01-31T23:59:59Z',
|
|
615
|
+
'where[person][id]': '456',
|
|
616
|
+
include: 'person',
|
|
617
|
+
order: '-created_at',
|
|
618
|
+
},
|
|
619
|
+
}));
|
|
620
|
+
});
|
|
621
|
+
});
|
|
622
|
+
//# sourceMappingURL=generator.test.js.map
|