From 705ed331faf8091c3901fff1635759a7a052473c Mon Sep 17 00:00:00 2001 From: Bas van den Aakster Date: Thu, 11 Sep 2025 13:03:07 +0200 Subject: [PATCH] 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 --- MIGRATION-v0.0.37.md | 225 ------------------------------------------- dev/test-helpers.ts | 216 ----------------------------------------- dev/test-setup.ts | 125 ------------------------ dev/test-trigger.ts | 104 -------------------- vitest.config.ts | 17 ---- 5 files changed, 687 deletions(-) delete mode 100644 MIGRATION-v0.0.37.md delete mode 100644 dev/test-helpers.ts delete mode 100644 dev/test-setup.ts delete mode 100644 dev/test-trigger.ts delete mode 100644 vitest.config.ts diff --git a/MIGRATION-v0.0.37.md b/MIGRATION-v0.0.37.md deleted file mode 100644 index 5465bc4..0000000 --- a/MIGRATION-v0.0.37.md +++ /dev/null @@ -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. \ No newline at end of file diff --git a/dev/test-helpers.ts b/dev/test-helpers.ts deleted file mode 100644 index 6b5ba0d..0000000 --- a/dev/test-helpers.ts +++ /dev/null @@ -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, 'TestTest 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, 'TestTest 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' - } -} \ No newline at end of file diff --git a/dev/test-setup.ts b/dev/test-setup.ts deleted file mode 100644 index b4a473c..0000000 --- a/dev/test-setup.ts +++ /dev/null @@ -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) - } -} \ No newline at end of file diff --git a/dev/test-trigger.ts b/dev/test-trigger.ts deleted file mode 100644 index 2eb0e9e..0000000 --- a/dev/test-trigger.ts +++ /dev/null @@ -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) \ No newline at end of file diff --git a/vitest.config.ts b/vitest.config.ts deleted file mode 100644 index 8acc4a3..0000000 --- a/vitest.config.ts +++ /dev/null @@ -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'] - }, -}) \ No newline at end of file