mirror of
https://github.com/xtr-dev/payload-automation.git
synced 2025-12-10 00:43:23 +00:00
Remove unused plugin modules and their associated tests
- Delete `init-global-hooks.ts`, `init-step-tasks.ts`, `init-webhook.ts`, and `init-workflow-hooks.ts` - Remove obsolete components: `TriggerWorkflowButton` and `WorkflowExecutionStatus` - Clean up unused trigger files: `webhook-trigger.ts` - Delete webhook-related integration tests: `webhook-triggers.spec.ts` - Streamline related documentation and improve maintainability by eliminating deprecated code
This commit is contained in:
@@ -24,13 +24,24 @@ if (!process.env.ROOT_DIR) {
|
||||
const buildConfigWithMemoryDB = async () => {
|
||||
// Use MongoDB adapter for testing instead of SQLite
|
||||
const { mongooseAdapter } = await import('@payloadcms/db-mongodb')
|
||||
|
||||
|
||||
return buildConfig({
|
||||
admin: {
|
||||
importMap: {
|
||||
baseDir: path.resolve(dirname, '..'),
|
||||
},
|
||||
},
|
||||
globals: [
|
||||
{
|
||||
slug: 'settings',
|
||||
fields: [
|
||||
{
|
||||
name: 'siteName',
|
||||
type: 'text'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
collections: [
|
||||
{
|
||||
slug: 'posts',
|
||||
@@ -96,14 +107,13 @@ const buildConfigWithMemoryDB = async () => {
|
||||
posts: true,
|
||||
media: true
|
||||
},
|
||||
globalTriggers: {
|
||||
settings: true
|
||||
},
|
||||
steps: [
|
||||
HttpRequestStepTask,
|
||||
CreateDocumentStepTask
|
||||
],
|
||||
triggers: [
|
||||
|
||||
],
|
||||
webhookPrefix: '/workflows-webhook'
|
||||
}),
|
||||
],
|
||||
secret: process.env.PAYLOAD_SECRET || 'test-secret_key',
|
||||
|
||||
@@ -1,483 +0,0 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
||||
import { getTestPayload, cleanDatabase } from './test-setup.js'
|
||||
|
||||
describe('Webhook Trigger Testing', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
it('should trigger workflow via webhook endpoint simulation', async () => {
|
||||
const payload = getTestPayload()
|
||||
|
||||
// Create a workflow with webhook trigger
|
||||
const workflow = await payload.create({
|
||||
collection: 'workflows',
|
||||
data: {
|
||||
name: 'Test Webhook - Basic Trigger',
|
||||
description: 'Tests basic webhook triggering',
|
||||
triggers: [
|
||||
{
|
||||
type: 'webhook-trigger',
|
||||
webhookPath: 'test-basic'
|
||||
}
|
||||
],
|
||||
steps: [
|
||||
{
|
||||
name: 'create-webhook-audit',
|
||||
step: 'create-document',
|
||||
collectionSlug: 'auditLog',
|
||||
data: {
|
||||
message: 'Webhook triggered successfully',
|
||||
user: '$.trigger.data.userId'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
expect(workflow).toBeDefined()
|
||||
|
||||
// Directly execute the workflow with webhook-like data
|
||||
const executor = (globalThis as any).__workflowExecutor
|
||||
if (!executor) {
|
||||
console.warn('⚠️ Workflow executor not available, skipping webhook execution')
|
||||
return
|
||||
}
|
||||
|
||||
// Simulate webhook trigger by directly executing the workflow
|
||||
const webhookData = {
|
||||
userId: 'webhook-test-user',
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
|
||||
const mockReq = {
|
||||
payload,
|
||||
user: null,
|
||||
headers: {}
|
||||
}
|
||||
|
||||
await executor.execute({
|
||||
workflow,
|
||||
trigger: {
|
||||
type: 'webhook',
|
||||
path: 'test-basic',
|
||||
data: webhookData,
|
||||
headers: {}
|
||||
},
|
||||
req: mockReq as any,
|
||||
payload
|
||||
})
|
||||
|
||||
console.log('✅ Workflow executed directly')
|
||||
|
||||
// Wait for workflow execution
|
||||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||||
|
||||
// Verify workflow run was created
|
||||
const runs = await payload.find({
|
||||
collection: 'workflow-runs',
|
||||
where: {
|
||||
workflow: {
|
||||
equals: workflow.id
|
||||
}
|
||||
},
|
||||
limit: 1
|
||||
})
|
||||
|
||||
expect(runs.totalDocs).toBe(1)
|
||||
expect(runs.docs[0].status).not.toBe('failed')
|
||||
|
||||
// Verify audit log was created
|
||||
const auditLogs = await payload.find({
|
||||
collection: 'auditLog',
|
||||
where: {
|
||||
message: {
|
||||
contains: 'Webhook triggered'
|
||||
}
|
||||
},
|
||||
limit: 1
|
||||
})
|
||||
|
||||
expect(auditLogs.totalDocs).toBe(1)
|
||||
console.log('✅ Webhook audit log created')
|
||||
}, 30000)
|
||||
|
||||
it('should handle webhook with complex data', async () => {
|
||||
const workflow = await payload.create({
|
||||
collection: 'workflows',
|
||||
data: {
|
||||
name: 'Test Webhook - Complex Data',
|
||||
description: 'Tests webhook with complex JSON data',
|
||||
triggers: [
|
||||
{
|
||||
type: 'webhook-trigger',
|
||||
webhookPath: 'test-complex'
|
||||
}
|
||||
],
|
||||
steps: [
|
||||
{
|
||||
name: 'echo-webhook-data',
|
||||
step: 'http-request-step',
|
||||
url: 'https://httpbin.org/post',
|
||||
method: 'POST',
|
||||
body: {
|
||||
originalData: '$.trigger.data',
|
||||
headers: '$.trigger.headers',
|
||||
path: '$.trigger.path'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
const complexData = {
|
||||
user: {
|
||||
id: 123,
|
||||
name: 'Test User',
|
||||
permissions: ['read', 'write']
|
||||
},
|
||||
event: {
|
||||
type: 'user_action',
|
||||
timestamp: new Date().toISOString(),
|
||||
metadata: {
|
||||
source: 'webhook-test',
|
||||
version: '1.0.0'
|
||||
}
|
||||
},
|
||||
nested: {
|
||||
deeply: {
|
||||
nested: {
|
||||
value: 'deep-test-value'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const response = await makeWebhookRequest('test-complex', complexData)
|
||||
expect(response.status).toBe(200)
|
||||
|
||||
// Wait for workflow execution
|
||||
await new Promise(resolve => setTimeout(resolve, 5000))
|
||||
|
||||
const runs = await payload.find({
|
||||
collection: 'workflow-runs',
|
||||
where: {
|
||||
workflow: {
|
||||
equals: workflow.id
|
||||
}
|
||||
},
|
||||
limit: 1
|
||||
})
|
||||
|
||||
expect(runs.totalDocs).toBe(1)
|
||||
expect(runs.docs[0].status).toBe('completed')
|
||||
|
||||
// Verify the complex data was properly passed through
|
||||
const stepOutput = runs.docs[0].context.steps['echo-webhook-data'].output
|
||||
expect(stepOutput.status).toBe(200)
|
||||
|
||||
const responseBody = JSON.parse(stepOutput.body)
|
||||
expect(responseBody.json.originalData.user.name).toBe('Test User')
|
||||
expect(responseBody.json.originalData.nested.deeply.nested.value).toBe('deep-test-value')
|
||||
|
||||
console.log('✅ Complex webhook data processed correctly')
|
||||
}, 30000)
|
||||
|
||||
it('should handle webhook conditions', async () => {
|
||||
const workflow = await payload.create({
|
||||
collection: 'workflows',
|
||||
data: {
|
||||
name: 'Test Webhook - Conditional',
|
||||
description: 'Tests conditional webhook execution',
|
||||
triggers: [
|
||||
{
|
||||
type: 'webhook-trigger',
|
||||
webhookPath: 'test-conditional',
|
||||
condition: '$.data.action == "important"'
|
||||
}
|
||||
],
|
||||
steps: [
|
||||
{
|
||||
name: 'conditional-audit',
|
||||
step: 'create-document',
|
||||
collectionSlug: 'auditLog',
|
||||
data: {
|
||||
message: 'Webhook condition met - important action'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
// First request - should NOT trigger (condition not met)
|
||||
const response1 = await makeWebhookRequest('test-conditional', {
|
||||
action: 'normal',
|
||||
data: 'test'
|
||||
})
|
||||
expect(response1.status).toBe(200)
|
||||
|
||||
// Second request - SHOULD trigger (condition met)
|
||||
const response2 = await makeWebhookRequest('test-conditional', {
|
||||
action: 'important',
|
||||
priority: 'high'
|
||||
})
|
||||
expect(response2.status).toBe(200)
|
||||
|
||||
// Wait for workflow execution
|
||||
await new Promise(resolve => setTimeout(resolve, 5000))
|
||||
|
||||
const runs = await payload.find({
|
||||
collection: 'workflow-runs',
|
||||
where: {
|
||||
workflow: {
|
||||
equals: workflow.id
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Should have exactly 1 run (only for the matching condition)
|
||||
expect(runs.totalDocs).toBe(1)
|
||||
expect(runs.docs[0].status).not.toBe('failed')
|
||||
|
||||
const auditLogs = await payload.find({
|
||||
collection: 'auditLog',
|
||||
where: {
|
||||
message: {
|
||||
contains: 'condition met'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
expect(auditLogs.totalDocs).toBe(1)
|
||||
console.log('✅ Webhook conditional execution working')
|
||||
}, 30000)
|
||||
|
||||
it('should handle webhook authentication headers', async () => {
|
||||
const workflow = await payload.create({
|
||||
collection: 'workflows',
|
||||
data: {
|
||||
name: 'Test Webhook - Headers',
|
||||
description: 'Tests webhook header processing',
|
||||
triggers: [
|
||||
{
|
||||
type: 'webhook-trigger',
|
||||
webhookPath: 'test-headers'
|
||||
}
|
||||
],
|
||||
steps: [
|
||||
{
|
||||
name: 'process-headers',
|
||||
step: 'http-request-step',
|
||||
url: 'https://httpbin.org/post',
|
||||
method: 'POST',
|
||||
body: {
|
||||
receivedHeaders: '$.trigger.headers',
|
||||
authorization: '$.trigger.headers.authorization',
|
||||
userAgent: '$.trigger.headers.user-agent'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
// Make webhook request with custom headers
|
||||
const webhookUrl = `${baseUrl}/api/workflows/webhook/test-headers`
|
||||
const response = await fetch(webhookUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer test-token-123',
|
||||
'User-Agent': 'Webhook-Test-Client/1.0',
|
||||
'X-Custom-Header': 'custom-value'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
test: 'header processing'
|
||||
})
|
||||
})
|
||||
|
||||
expect(response.status).toBe(200)
|
||||
|
||||
// Wait for workflow execution
|
||||
await new Promise(resolve => setTimeout(resolve, 5000))
|
||||
|
||||
const runs = await payload.find({
|
||||
collection: 'workflow-runs',
|
||||
where: {
|
||||
workflow: {
|
||||
equals: workflow.id
|
||||
}
|
||||
},
|
||||
limit: 1
|
||||
})
|
||||
|
||||
expect(runs.totalDocs).toBe(1)
|
||||
expect(runs.docs[0].status).toBe('completed')
|
||||
|
||||
// Verify headers were captured and processed
|
||||
const stepOutput = runs.docs[0].context.steps['process-headers'].output
|
||||
const responseBody = JSON.parse(stepOutput.body)
|
||||
|
||||
expect(responseBody.json.authorization).toBe('Bearer test-token-123')
|
||||
expect(responseBody.json.userAgent).toBe('Webhook-Test-Client/1.0')
|
||||
|
||||
console.log('✅ Webhook headers processed correctly')
|
||||
}, 30000)
|
||||
|
||||
it('should handle multiple concurrent webhook requests', async () => {
|
||||
const workflow = await payload.create({
|
||||
collection: 'workflows',
|
||||
data: {
|
||||
name: 'Test Webhook - Concurrent',
|
||||
description: 'Tests concurrent webhook processing',
|
||||
triggers: [
|
||||
{
|
||||
type: 'webhook-trigger',
|
||||
webhookPath: 'test-concurrent'
|
||||
}
|
||||
],
|
||||
steps: [
|
||||
{
|
||||
name: 'concurrent-audit',
|
||||
step: 'create-document',
|
||||
collectionSlug: 'auditLog',
|
||||
data: {
|
||||
message: 'Concurrent webhook execution',
|
||||
requestId: '$.trigger.data.requestId'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
// Make multiple concurrent webhook requests
|
||||
const concurrentRequests = Array.from({ length: 5 }, (_, i) =>
|
||||
makeWebhookRequest('test-concurrent', {
|
||||
requestId: `concurrent-${i + 1}`,
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
)
|
||||
|
||||
const responses = await Promise.all(concurrentRequests)
|
||||
responses.forEach(response => {
|
||||
expect(response.status).toBe(200)
|
||||
})
|
||||
|
||||
// Wait for all workflow executions
|
||||
await new Promise(resolve => setTimeout(resolve, 8000))
|
||||
|
||||
const runs = await payload.find({
|
||||
collection: 'workflow-runs',
|
||||
where: {
|
||||
workflow: {
|
||||
equals: workflow.id
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
expect(runs.totalDocs).toBe(5)
|
||||
|
||||
// Verify all runs completed successfully
|
||||
const failedRuns = runs.docs.filter(run => run.status === 'failed')
|
||||
expect(failedRuns).toHaveLength(0)
|
||||
|
||||
// Verify all audit logs were created
|
||||
const auditLogs = await payload.find({
|
||||
collection: 'auditLog',
|
||||
where: {
|
||||
message: {
|
||||
contains: 'Concurrent webhook'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
expect(auditLogs.totalDocs).toBe(5)
|
||||
console.log('✅ Concurrent webhook requests processed successfully')
|
||||
}, 35000)
|
||||
|
||||
it('should handle non-existent webhook paths gracefully', async () => {
|
||||
// Test that workflows with non-matching webhook paths don't get triggered
|
||||
const workflow = await payload.create({
|
||||
collection: 'workflows',
|
||||
data: {
|
||||
name: 'Test Webhook - Non-existent Path',
|
||||
description: 'Should not be triggered by different path',
|
||||
triggers: [
|
||||
{
|
||||
type: 'webhook-trigger',
|
||||
webhookPath: 'specific-path'
|
||||
}
|
||||
],
|
||||
steps: [
|
||||
{
|
||||
name: 'create-audit',
|
||||
step: 'create-document',
|
||||
collectionSlug: 'auditLog',
|
||||
data: {
|
||||
message: 'This should not be created'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
// Simulate trying to trigger with wrong path - should not execute workflow
|
||||
const initialRuns = await payload.find({
|
||||
collection: 'workflow-runs',
|
||||
where: {
|
||||
workflow: {
|
||||
equals: workflow.id
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
expect(initialRuns.totalDocs).toBe(0)
|
||||
console.log('✅ Non-existent webhook path handled: no workflow runs created')
|
||||
}, 10000)
|
||||
|
||||
it('should handle malformed webhook JSON', async () => {
|
||||
const webhookUrl = `${baseUrl}/api/workflows/webhook/test-malformed`
|
||||
|
||||
// First create a workflow to receive the malformed request
|
||||
const workflow = await payload.create({
|
||||
collection: 'workflows',
|
||||
data: {
|
||||
name: 'Test Webhook - Malformed JSON',
|
||||
description: 'Tests malformed JSON handling',
|
||||
triggers: [
|
||||
{
|
||||
type: 'webhook-trigger',
|
||||
webhookPath: 'test-malformed'
|
||||
}
|
||||
],
|
||||
steps: [
|
||||
{
|
||||
name: 'malformed-test',
|
||||
step: 'create-document',
|
||||
collectionSlug: 'auditLog',
|
||||
data: {
|
||||
message: 'Processed malformed request'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
// Send malformed JSON
|
||||
const response = await fetch(webhookUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: '{"malformed": json, "missing": quotes}'
|
||||
})
|
||||
|
||||
// Should handle malformed JSON gracefully
|
||||
expect([400, 422]).toContain(response.status)
|
||||
console.log('✅ Malformed JSON handled:', response.status)
|
||||
}, 15000)
|
||||
})
|
||||
Reference in New Issue
Block a user