mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
fix: Load remote resources even if expressions in non requried parameters resolve (#6987)
Github issue / Community forum post (link here to close automatically):
This commit is contained in:
18
packages/nodes-base/nodes/E2eTest/E2eTest.node.json
Normal file
18
packages/nodes-base/nodes/E2eTest/E2eTest.node.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.e2eTest",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"details": "The is a test node for e2e testing.",
|
||||
"categories": ["Core Nodes"],
|
||||
"resources": {
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.editimage/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"subcategories": {
|
||||
"Core Nodes": ["Helpers"]
|
||||
},
|
||||
"e2e": true
|
||||
}
|
||||
207
packages/nodes-base/nodes/E2eTest/E2eTest.node.ts
Normal file
207
packages/nodes-base/nodes/E2eTest/E2eTest.node.ts
Normal file
@@ -0,0 +1,207 @@
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
INodeExecutionData,
|
||||
INodeListSearchResult,
|
||||
INodePropertyOptions,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
ResourceMapperFields,
|
||||
} from 'n8n-workflow';
|
||||
import { remoteOptions, resourceMapperFields, returnData, searchOptions } from './mock';
|
||||
|
||||
export class E2eTest implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'E2E Test',
|
||||
name: 'e2eTest',
|
||||
icon: 'fa:play',
|
||||
group: ['output'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"]}}',
|
||||
description: 'Dummy node used for e2e testing',
|
||||
defaults: {
|
||||
name: 'E2E Test',
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Remote Options',
|
||||
value: 'remoteOptions',
|
||||
},
|
||||
{
|
||||
name: 'Resource Locator',
|
||||
value: 'resourceLocator',
|
||||
},
|
||||
{
|
||||
name: 'Resource Mapping Component',
|
||||
value: 'resourceMapper',
|
||||
},
|
||||
],
|
||||
default: 'remoteOptions',
|
||||
},
|
||||
{
|
||||
displayName: 'Field ID',
|
||||
name: 'fieldId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Remote Options Name or ID',
|
||||
name: 'remoteOptions',
|
||||
description:
|
||||
'Remote options to load. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsDependsOn: ['fieldId'],
|
||||
loadOptionsMethod: 'getOptions',
|
||||
},
|
||||
required: true,
|
||||
default: [],
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['remoteOptions'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Resource Locator',
|
||||
name: 'rlc',
|
||||
type: 'resourceLocator',
|
||||
default: { mode: 'list', value: '' },
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['resourceLocator'],
|
||||
},
|
||||
},
|
||||
modes: [
|
||||
{
|
||||
displayName: 'From List',
|
||||
name: 'list',
|
||||
type: 'list',
|
||||
typeOptions: {
|
||||
searchListMethod: 'optionsSearch',
|
||||
searchable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'By URL',
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
placeholder: 'https://example.com/user/a4071e98-7d40-41fb-8911-ce3e7bf94fb2',
|
||||
validation: [
|
||||
{
|
||||
type: 'regex',
|
||||
properties: {
|
||||
regex:
|
||||
'https://example.com/user/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}',
|
||||
errorMessage: 'Not a valid example URL',
|
||||
},
|
||||
},
|
||||
],
|
||||
extractValue: {
|
||||
type: 'regex',
|
||||
regex:
|
||||
'https://example.com/user/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})',
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
validation: [
|
||||
{
|
||||
type: 'regex',
|
||||
properties: {
|
||||
regex: '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}',
|
||||
errorMessage: 'Not a valid UUI',
|
||||
},
|
||||
},
|
||||
],
|
||||
placeholder: 'a4071e98-7d40-41fb-8911-ce3e7bf94fb2',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Resource Mapping Component',
|
||||
name: 'resourceMapper',
|
||||
type: 'resourceMapper',
|
||||
noDataExpression: true,
|
||||
default: {
|
||||
mappingMode: 'defineBelow',
|
||||
value: null,
|
||||
},
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsDependsOn: ['fieldId'],
|
||||
resourceMapper: {
|
||||
resourceMapperMethod: 'getMappingColumns',
|
||||
mode: 'upsert',
|
||||
fieldWords: {
|
||||
singular: 'column',
|
||||
plural: 'columns',
|
||||
},
|
||||
addAllFields: true,
|
||||
multiKeyMatch: false,
|
||||
},
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['resourceMapper'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Other Non Important Field',
|
||||
name: 'otherField',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
loadOptions: {
|
||||
async getOptions(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
return remoteOptions;
|
||||
},
|
||||
},
|
||||
listSearch: {
|
||||
async optionsSearch(
|
||||
this: ILoadOptionsFunctions,
|
||||
filter?: string,
|
||||
paginationToken?: string,
|
||||
): Promise<INodeListSearchResult> {
|
||||
const pageSize = 5;
|
||||
let results = searchOptions;
|
||||
if (filter) {
|
||||
results = results.filter((option) => option.name.includes(filter));
|
||||
}
|
||||
|
||||
const offset = paginationToken ? parseInt(paginationToken, 10) : 0;
|
||||
results = results.slice(offset, offset + pageSize);
|
||||
|
||||
return {
|
||||
results,
|
||||
paginationToken: offset + pageSize,
|
||||
};
|
||||
},
|
||||
},
|
||||
resourceMapping: {
|
||||
async getMappingColumns(this: ILoadOptionsFunctions): Promise<ResourceMapperFields> {
|
||||
return resourceMapperFields;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
return this.prepareOutputData(returnData);
|
||||
}
|
||||
}
|
||||
64
packages/nodes-base/nodes/E2eTest/mock.ts
Normal file
64
packages/nodes-base/nodes/E2eTest/mock.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { array, name, uuid } from 'minifaker';
|
||||
import 'minifaker/locales/en';
|
||||
import type {
|
||||
INodeExecutionData,
|
||||
INodeListSearchResult,
|
||||
INodePropertyOptions,
|
||||
ResourceMapperFields,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export const returnData: INodeExecutionData[] = [
|
||||
{
|
||||
json: {
|
||||
id: '23423532',
|
||||
name: 'Hello World',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const remoteOptions: INodePropertyOptions[] = [
|
||||
{
|
||||
name: 'Resource 1',
|
||||
value: 'resource1',
|
||||
},
|
||||
{
|
||||
name: 'Resource 2',
|
||||
value: 'resource2',
|
||||
},
|
||||
{
|
||||
name: 'Resource 3',
|
||||
value: 'resource3',
|
||||
},
|
||||
];
|
||||
|
||||
export const resourceMapperFields: ResourceMapperFields = {
|
||||
fields: [
|
||||
{
|
||||
id: 'id',
|
||||
displayName: 'ID',
|
||||
defaultMatch: true,
|
||||
canBeUsedToMatch: true,
|
||||
required: true,
|
||||
display: true,
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
id: 'name',
|
||||
displayName: 'Name',
|
||||
defaultMatch: false,
|
||||
canBeUsedToMatch: false,
|
||||
required: false,
|
||||
display: true,
|
||||
type: 'string',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const searchOptions: INodeListSearchResult['results'] = array(100, () => {
|
||||
const value = uuid.v4();
|
||||
return {
|
||||
name: name(),
|
||||
value,
|
||||
url: 'https://example.com/user/' + value,
|
||||
};
|
||||
});
|
||||
@@ -466,6 +466,7 @@
|
||||
"dist/nodes/Dropbox/Dropbox.node.js",
|
||||
"dist/nodes/Dropcontact/Dropcontact.node.js",
|
||||
"dist/nodes/EditImage/EditImage.node.js",
|
||||
"dist/nodes/E2eTest/E2eTest.node.js",
|
||||
"dist/nodes/Egoi/Egoi.node.js",
|
||||
"dist/nodes/Elastic/Elasticsearch/Elasticsearch.node.js",
|
||||
"dist/nodes/Elastic/ElasticSecurity/ElasticSecurity.node.js",
|
||||
|
||||
Reference in New Issue
Block a user