first commit
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
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
This commit is contained in:
+306
@@ -0,0 +1,306 @@
|
||||
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)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
Reference in New Issue
Block a user