Remove migration guide, test helpers, and test setup files

- Delete `MIGRATION-v0.0.37.md` as it is no longer necessary
- Remove outdated files: `test-helpers.ts`, `test-setup.ts`, `test-trigger.ts`, and `vitest.config.ts`
- Streamline project by eliminating obsolete and unused test-related files and configurations
This commit is contained in:
2025-09-11 13:03:07 +02:00
parent e0b13d3515
commit 705ed331fa
5 changed files with 0 additions and 687 deletions

View File

@@ -1,225 +0,0 @@
# Migration Guide: v0.0.36 to v0.0.37
## Overview
Version 0.0.37 introduces significant refactoring and cleanup changes focused on simplifying the plugin architecture and removing unused features. This version removes several deprecated components and consolidates trigger handling.
## Breaking Changes
### 1. Removed Components and Files
The following components and modules have been completely removed:
#### Components
- `TriggerWorkflowButton` - Manual workflow triggering component
- `WorkflowExecutionStatus` - Workflow execution status display component
#### Plugin Modules
- `init-global-hooks.ts` - Global hook initialization (functionality moved to main plugin)
- `init-step-tasks.ts` - Step task initialization (functionality integrated elsewhere)
- `init-webhook.ts` - Webhook initialization (functionality removed)
- `init-workflow-hooks.ts` - Workflow hook initialization (functionality moved to main plugin)
#### Triggers
- `webhook-trigger.ts` - Webhook trigger support has been removed
- `cron-trigger.ts` - Cron/scheduled trigger support has been removed
- `cron-scheduler.ts` - Cron scheduling system has been removed
#### Tests
- `webhook-triggers.spec.ts` - Webhook trigger integration tests
### 2. Cron/Scheduled Workflows Removal
Cron trigger functionality has been completely removed from the plugin. If you were using cron triggers in your workflows:
**Migration Path:**
- Use external scheduling services like GitHub Actions or Vercel Cron
- Trigger workflows via webhook endpoints from external schedulers
- Implement custom scheduling in your application using libraries like `node-cron`
**Example with GitHub Actions:**
```yaml
name: Trigger Workflow
on:
schedule:
- cron: '0 9 * * *' # Daily at 9 AM
jobs:
trigger:
runs-on: ubuntu-latest
steps:
- name: Trigger Workflow
run: |
curl -X POST https://your-app.com/api/workflows/trigger/your-workflow-id
```
### 3. Webhook Trigger Removal
Webhook triggers have been removed. If you were using webhook triggers:
**Migration Path:**
- Implement custom webhook endpoints in your PayloadCMS application
- Use collection or global hooks to trigger workflows based on document changes
- Create manual trigger endpoints using the workflow executor directly
### 4. Architecture Changes
#### ExecutorRegistry Removal
The `executorRegistry` singleton pattern has been removed. WorkflowExecutor instances are now created on-demand for each execution.
**What this means:**
- No shared state between workflow executions
- Each execution is completely independent
- Better memory management and isolation
#### Hook Registration Consolidation
Hook registration logic has been consolidated into the main plugin file:
- Collection hooks are now registered directly in `plugin/index.ts`
- Global hooks are handled through the new `plugin/global-hook.ts` module
- Simplified hook management with better TypeScript typing
## Non-Breaking Changes
### 1. Trigger Module Refactoring
Triggers have been reorganized into a dedicated `triggers/` directory with improved modularity:
- `triggers/collection-trigger.ts` - Collection-based triggers
- `triggers/global-trigger.ts` - Global document triggers
- `triggers/index.ts` - Trigger exports
- `triggers/types.ts` - Trigger type definitions
### 2. Field Helper Improvements
New `triggerField` helper function standardizes virtual field creation across all trigger modules:
```typescript
// Before (manual virtual field creation)
{
name: '__builtin_collection',
type: 'text',
admin: { hidden: true },
virtual: true,
access: { read: () => false, update: () => false }
}
// After (using helper)
triggerField('collection', {
type: 'text',
// helper handles virtual field setup automatically
})
```
### 3. TypeScript Improvements
- Replaced 'any' types with proper TypeScript types
- Added `CollectionAfterChangeHook` and `PayloadRequest` type usage
- Improved type safety throughout the codebase
### 4. Code Organization
#### New File Structure
```
src/
├── plugin/
│ ├── collection-hook.ts # Collection hook logic
│ ├── global-hook.ts # Global hook logic (new)
│ └── index.ts # Main plugin (consolidated)
├── triggers/ # Trigger modules (new directory)
├── fields/
│ └── parameter.ts # Moved from triggers/helpers.ts
```
#### ESLint Configuration
- Disabled `perfectionist/sort-object-types` and `perfectionist/sort-objects` rules
- Allows natural object property ordering without enforced alphabetical sorting
## Migration Steps
### 1. Update Imports
If you were importing removed components or modules, remove these imports:
```typescript
// Remove these imports - no longer available
import { TriggerWorkflowButton } from '@xtr-dev/payload-automation/client'
import { WorkflowExecutionStatus } from '@xtr-dev/payload-automation/client'
```
### 2. Update Workflow Configurations
If your workflows used cron or webhook triggers, you'll need to modify them:
**Before:**
```javascript
{
trigger: {
type: 'cron',
schedule: '0 9 * * *'
}
}
```
**After:**
```javascript
{
trigger: {
type: 'collection', // Use collection or global triggers instead
collection: 'your-collection',
operation: 'create'
}
}
```
### 3. Replace Webhook Functionality
If you were using webhook triggers, implement custom webhook handling:
```typescript
// In your PayloadCMS config
export default buildConfig({
endpoints: [
{
path: '/trigger-workflow/:workflowId',
method: 'post',
handler: async (req) => {
const { workflowId } = req.params
// Implement your workflow triggering logic here
// Use the WorkflowExecutor directly if needed
}
}
]
})
```
### 4. Update Custom Components
If you built custom components using the removed ones as reference, update them to work with the new architecture.
## Benefits of This Release
1. **Simplified Architecture**: Consolidated plugin initialization reduces complexity
2. **Better Memory Management**: On-demand executor creation eliminates shared state issues
3. **Improved Type Safety**: Proper TypeScript typing throughout
4. **Reduced Bundle Size**: Removal of unused code reduces package size
5. **Better Maintainability**: Cleaner code organization and module structure
6. **More Reliable**: External scheduling is more robust than in-process cron jobs
## Testing Your Migration
After migrating:
1. **Test Existing Workflows**: Ensure collection and global triggers still work as expected
2. **Verify External Triggers**: Test any external webhook or scheduling implementations
3. **Check Custom Components**: Validate any custom UI components that interact with workflows
4. **Run Integration Tests**: Execute your test suite to catch any breaking changes
## Support
If you encounter issues migrating from v0.0.36 to v0.0.37:
1. Check that you're not using any of the removed components or features
2. Verify your workflow trigger types are supported (collection, global, manual)
3. Update any custom integrations that relied on removed modules
4. Consider the external scheduling alternatives for cron functionality
For additional support, please refer to the plugin documentation or open an issue in the project repository.

View File

@@ -1,216 +0,0 @@
import nock from 'nock'
/**
* Mock HTTP requests to httpbin.org for testing
*/
export const mockHttpBin = {
/**
* Mock a successful POST request to httpbin.org/post
*/
mockPost: (expectedData?: any) => {
return nock('https://httpbin.org')
.post('/post')
.reply(200, {
args: {},
data: JSON.stringify(expectedData || {}),
files: {},
form: {},
headers: {
'Accept': '*/*',
'Accept-Encoding': 'br, gzip, deflate',
'Accept-Language': '*',
'Content-Type': 'application/json',
'Host': 'httpbin.org',
'Sec-Fetch-Mode': 'cors',
'User-Agent': 'PayloadCMS-Automation/1.0'
},
json: expectedData || {},
origin: '127.0.0.1',
url: 'https://httpbin.org/post'
}, {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true'
})
},
/**
* Mock a GET request to httpbin.org/get
*/
mockGet: () => {
return nock('https://httpbin.org')
.get('/get')
.reply(200, {
args: {},
headers: {
'Accept': '*/*',
'Host': 'httpbin.org',
'User-Agent': 'PayloadCMS-Automation/1.0'
},
origin: '127.0.0.1',
url: 'https://httpbin.org/get'
})
},
/**
* Mock HTTP timeout
*/
mockTimeout: (path: string = '/delay/10') => {
return nock('https://httpbin.org')
.get(path)
.replyWithError({
code: 'ECONNABORTED',
message: 'timeout of 2000ms exceeded'
})
},
/**
* Mock HTTP error responses
*/
mockError: (status: number, path: string = '/status/' + status) => {
return nock('https://httpbin.org')
.get(path)
.reply(status, {
error: `HTTP ${status} Error`,
message: `Mock ${status} response`
})
},
/**
* Mock invalid URL to simulate network errors
*/
mockNetworkError: (url: string = 'invalid-url-that-will-fail') => {
return nock('https://' + url)
.get('/')
.replyWithError({
code: 'ENOTFOUND',
message: `getaddrinfo ENOTFOUND ${url}`
})
},
/**
* Mock HTML response (non-JSON)
*/
mockHtml: () => {
return nock('https://httpbin.org')
.get('/html')
.reply(200, '<!DOCTYPE html><html><head><title>Test</title></head><body>Test HTML</body></html>', {
'Content-Type': 'text/html'
})
},
/**
* Mock all common endpoints for error scenarios
*/
mockAllErrorScenarios: () => {
// HTML response for invalid JSON test
nock('https://httpbin.org')
.get('/html')
.reply(200, '<!DOCTYPE html><html><head><title>Test</title></head><body>Test HTML</body></html>', {
'Content-Type': 'text/html'
})
// 404 error
nock('https://httpbin.org')
.get('/status/404')
.reply(404, {
error: 'Not Found',
message: 'The requested resource was not found'
})
// 500 error
nock('https://httpbin.org')
.get('/status/500')
.reply(500, {
error: 'Internal Server Error',
message: 'Server encountered an error'
})
// 503 error for retry tests
nock('https://httpbin.org')
.get('/status/503')
.times(3) // Allow 3 retries
.reply(503, {
error: 'Service Unavailable',
message: 'Service is temporarily unavailable'
})
// POST endpoint for circular reference and other POST tests
nock('https://httpbin.org')
.post('/post')
.times(5) // Allow multiple POST requests
.reply(200, (uri, requestBody) => ({
args: {},
data: JSON.stringify(requestBody),
json: requestBody,
url: 'https://httpbin.org/post'
}))
},
/**
* Clean up all nock mocks
*/
cleanup: () => {
nock.cleanAll()
}
}
/**
* Test fixtures for common workflow configurations
*/
export const testFixtures = {
// Function to create workflow data that bypasses parameter validation
createWorkflow: async (payload: any, workflowData: any) => {
// Insert directly into database to bypass parameter field validation
const result = await payload.db.create({
collection: 'workflows',
data: workflowData
})
return result
},
basicWorkflow: {
name: 'Test Basic Workflow',
description: 'Basic workflow for testing',
triggers: [
{
type: 'collection-hook' as const,
parameters: {
collectionSlug: 'posts',
hook: 'afterChange'
}
}
]
},
httpRequestStep: (url: string = 'https://httpbin.org/post', expectedData?: any) => ({
name: 'http-request',
type: 'http-request-step',
parameters: {
url,
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: expectedData || {
message: 'Test request',
data: '$.trigger.doc'
}
}
}),
createDocumentStep: (collectionSlug: string = 'auditLog') => ({
name: 'create-audit',
type: 'create-document',
parameters: {
collectionSlug,
data: {
message: 'Test document created',
sourceId: '$.trigger.doc.id'
}
}
}),
testPost: {
content: 'Test post content for workflow trigger'
}
}

View File

@@ -1,125 +0,0 @@
import { MongoMemoryReplSet } from 'mongodb-memory-server'
import { getPayload } from 'payload'
import type { Payload } from 'payload'
import nock from 'nock'
import config from './payload.config.js'
// Configure nock to intercept fetch requests properly in Node.js 22
nock.disableNetConnect()
nock.enableNetConnect('127.0.0.1')
// Set global fetch to use undici for proper nock interception
import { fetch } from 'undici'
global.fetch = fetch
let mongod: MongoMemoryReplSet | null = null
let payload: Payload | null = null
// Global test setup - runs once for all tests
beforeAll(async () => {
// Start MongoDB in-memory replica set
mongod = await MongoMemoryReplSet.create({
replSet: {
count: 1,
dbName: 'payload-test',
},
})
const mongoUri = mongod.getUri()
process.env.DATABASE_URI = mongoUri
console.log('🚀 MongoDB in-memory server started:', mongoUri)
// Initialize Payload with test config
payload = await getPayload({
config: await config,
local: true
})
console.log('✅ Payload initialized for testing')
}, 60000)
// Global test teardown - runs once after all tests
afterAll(async () => {
if (payload) {
console.log('🛑 Shutting down Payload...')
// Payload doesn't have a shutdown method, but we can clear the cache
delete (global as any).payload
payload = null
}
if (mongod) {
console.log('🛑 Stopping MongoDB in-memory server...')
await mongod.stop()
mongod = null
}
}, 30000)
// Export payload instance for tests
export const getTestPayload = () => {
if (!payload) {
throw new Error('Payload not initialized. Make sure test setup has run.')
}
return payload
}
// Helper to clean all collections
export const cleanDatabase = async () => {
if (!payload) return
try {
// Clean up workflow runs first (child records)
const runs = await payload.find({
collection: 'workflow-runs',
limit: 1000
})
for (const run of runs.docs) {
await payload.delete({
collection: 'workflow-runs',
id: run.id
})
}
// Clean up workflows
const workflows = await payload.find({
collection: 'workflows',
limit: 1000
})
for (const workflow of workflows.docs) {
await payload.delete({
collection: 'workflows',
id: workflow.id
})
}
// Clean up audit logs
const auditLogs = await payload.find({
collection: 'auditLog',
limit: 1000
})
for (const log of auditLogs.docs) {
await payload.delete({
collection: 'auditLog',
id: log.id
})
}
// Clean up posts
const posts = await payload.find({
collection: 'posts',
limit: 1000
})
for (const post of posts.docs) {
await payload.delete({
collection: 'posts',
id: post.id
})
}
} catch (error) {
console.warn('Database cleanup failed:', error)
}
}

View File

@@ -1,104 +0,0 @@
import type { Payload } from 'payload'
import { getPayload } from 'payload'
import config from './payload.config'
async function testWorkflowTrigger() {
console.log('Starting workflow trigger test...')
// Get payload instance
const payload = await getPayload({ config })
try {
// Create a test user
const user = await payload.create({
collection: 'users',
data: {
email: 'test@example.com',
password: 'password123'
}
})
console.log('Created test user:', user.id)
// Create a workflow with collection trigger
const workflow = await payload.create({
collection: 'workflows',
data: {
name: 'Test Post Creation Workflow',
description: 'Triggers when a post is created',
triggers: [
{
type: 'collection-trigger',
collectionSlug: 'posts',
operation: 'create'
}
],
steps: [
{
name: 'log-post',
step: 'http-request-step',
input: {
url: 'https://httpbin.org/post',
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: {
message: 'Post created',
postId: '$.trigger.doc.id',
postTitle: '$.trigger.doc.title'
}
}
}
]
},
user: user.id
})
console.log('Created workflow:', workflow.id)
// Create a post to trigger the workflow
console.log('Creating post to trigger workflow...')
const post = await payload.create({
collection: 'posts',
data: {
title: 'Test Post',
content: 'This should trigger the workflow',
_status: 'published'
},
user: user.id
})
console.log('Created post:', post.id)
// Wait a bit for workflow to execute
await new Promise(resolve => setTimeout(resolve, 2000))
// Check for workflow runs
const runs = await payload.find({
collection: 'workflow-runs',
where: {
workflow: {
equals: workflow.id
}
}
})
console.log('Workflow runs found:', runs.totalDocs)
if (runs.totalDocs > 0) {
console.log('✅ SUCCESS: Workflow was triggered!')
console.log('Run status:', runs.docs[0].status)
console.log('Run context:', JSON.stringify(runs.docs[0].context, null, 2))
} else {
console.log('❌ FAILURE: Workflow was not triggered')
}
} catch (error) {
console.error('Test failed:', error)
} finally {
await payload.shutdown()
}
}
testWorkflowTrigger().catch(console.error)

View File

@@ -1,17 +0,0 @@
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
environment: 'node',
threads: false, // Prevent port/DB conflicts
pool: 'forks',
poolOptions: {
forks: {
singleFork: true
}
},
testTimeout: 30000, // 30 second timeout for integration tests
setupFiles: ['./dev/test-setup.ts']
},
})