Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
307 lines
8.1 KiB
TypeScript
307 lines
8.1 KiB
TypeScript
import { RuleTester } from '@typescript-eslint/rule-tester';
|
|
|
|
import { CredentialDocumentationUrlRule } from './credential-documentation-url.js';
|
|
|
|
const ruleTester = new RuleTester();
|
|
|
|
function createCredentialCode(documentationUrl: string): string {
|
|
return `
|
|
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
|
|
export class TestCredential implements ICredentialType {
|
|
name = 'testApi';
|
|
displayName = 'Test API';
|
|
documentationUrl = '${documentationUrl}';
|
|
|
|
properties: INodeProperties[] = [];
|
|
}`;
|
|
}
|
|
|
|
function createCredentialWithoutDocUrl(): string {
|
|
return `
|
|
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
|
|
export class TestCredential implements ICredentialType {
|
|
name = 'testApi';
|
|
displayName = 'Test API';
|
|
|
|
properties: INodeProperties[] = [];
|
|
}`;
|
|
}
|
|
|
|
function createRegularClass(): string {
|
|
return `
|
|
export class RegularClass {
|
|
documentationUrl = 'invalid-url';
|
|
}`;
|
|
}
|
|
|
|
ruleTester.run('credential-documentation-url', CredentialDocumentationUrlRule, {
|
|
valid: [
|
|
{
|
|
name: 'valid URL with default options (URLs only)',
|
|
code: createCredentialCode('https://example.com/docs'),
|
|
},
|
|
{
|
|
name: 'valid URL with explicit options',
|
|
code: createCredentialCode('https://example.com/docs'),
|
|
options: [{ allowUrls: true, allowSlugs: false }],
|
|
},
|
|
{
|
|
name: 'valid lowercase slug when slugs are allowed',
|
|
code: createCredentialCode('myservice'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
},
|
|
{
|
|
name: 'valid lowercase slug with slashes when slugs are allowed',
|
|
code: createCredentialCode('myservice/advanced/config'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
},
|
|
{
|
|
name: 'valid URL when both URLs and slugs are allowed',
|
|
code: createCredentialCode('https://example.com/docs'),
|
|
options: [{ allowUrls: true, allowSlugs: true }],
|
|
},
|
|
{
|
|
name: 'valid lowercase slug when both URLs and slugs are allowed',
|
|
code: createCredentialCode('myservice/config'),
|
|
options: [{ allowUrls: true, allowSlugs: true }],
|
|
},
|
|
{
|
|
name: 'credential without documentationUrl should not trigger',
|
|
code: createCredentialWithoutDocUrl(),
|
|
},
|
|
{
|
|
name: 'class not implementing ICredentialType should be ignored',
|
|
code: createRegularClass(),
|
|
},
|
|
{
|
|
name: 'valid lowercase slug with multiple segments',
|
|
code: createCredentialCode('myservice/somefeature/advancedconfig'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
},
|
|
{
|
|
name: 'valid lowercase alphanumeric slug',
|
|
code: createCredentialCode('myservice123'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
},
|
|
{
|
|
name: 'valid lowercase alphanumeric slug with slashes',
|
|
code: createCredentialCode('myservice123/config456'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
},
|
|
],
|
|
invalid: [
|
|
{
|
|
name: 'invalid URL with default options',
|
|
code: createCredentialCode('invalid-url'),
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: 'invalid-url',
|
|
expectedFormats: 'a valid URL',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'slug not allowed with default options',
|
|
code: createCredentialCode('myservice'),
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: 'myservice',
|
|
expectedFormats: 'a valid URL',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'slug with special characters should not be autofixable',
|
|
code: createCredentialCode('My-Service'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: 'My-Service',
|
|
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'uppercase slug should be autofixable',
|
|
code: createCredentialCode('MyService'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
output: createCredentialCode('myservice'),
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: 'MyService',
|
|
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'invalid URL when only URLs are allowed',
|
|
code: createCredentialCode('not-a-valid-url'),
|
|
options: [{ allowUrls: true, allowSlugs: false }],
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: 'not-a-valid-url',
|
|
expectedFormats: 'a valid URL',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'invalid when neither URLs nor slugs are allowed',
|
|
code: createCredentialCode('https://example.com'),
|
|
options: [{ allowUrls: false, allowSlugs: false }],
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: 'https://example.com',
|
|
expectedFormats: 'a valid format (none configured)',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'slug with invalid characters (special chars) should not be autofixable',
|
|
code: createCredentialCode('my@service/config'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: 'my@service/config',
|
|
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'slug with uppercase segment should be autofixable',
|
|
code: createCredentialCode('myService/Config'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
output: createCredentialCode('myservice/config'),
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: 'myService/Config',
|
|
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'slug with hyphens should not be autofixable',
|
|
code: createCredentialCode('myservice/advanced-config'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: 'myservice/advanced-config',
|
|
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'slug with underscores should not be autofixable',
|
|
code: createCredentialCode('my_service/config_advanced'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: 'my_service/config_advanced',
|
|
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'invalid value when both formats are allowed - shows both in error message',
|
|
code: createCredentialCode('Invalid-Value!'),
|
|
options: [{ allowUrls: true, allowSlugs: true }],
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: 'Invalid-Value!',
|
|
expectedFormats: 'a valid URL or a lowercase alphanumeric slug (can contain slashes)',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'empty string should be invalid with default options',
|
|
code: createCredentialCode(''),
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: '',
|
|
expectedFormats: 'a valid URL',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'empty string should be invalid when slugs are allowed',
|
|
code: createCredentialCode(''),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: '',
|
|
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'mixed case slug with numbers should be autofixable',
|
|
code: createCredentialCode('MyService123/Config456'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
output: createCredentialCode('myservice123/config456'),
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: 'MyService123/Config456',
|
|
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'slug starting with number should be invalid and not autofixable',
|
|
code: createCredentialCode('123service/config'),
|
|
options: [{ allowUrls: false, allowSlugs: true }],
|
|
errors: [
|
|
{
|
|
messageId: 'invalidDocumentationUrl',
|
|
data: {
|
|
value: '123service/config',
|
|
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
});
|