diff --git a/debug-customer-setup.js b/debug-customer-setup.js new file mode 100644 index 0000000..0ec15c2 --- /dev/null +++ b/debug-customer-setup.js @@ -0,0 +1,67 @@ +// Debug script to identify customer-side configuration issues +// Run this in your environment to pinpoint the problem + +console.log('๐Ÿ” === CUSTOMER ENVIRONMENT DEBUGGING ===') + +// This script needs to be run in your actual environment +// Copy this logic into your own debugging script + +const debugChecklist = { + "Plugin Version": "Check package.json for @xtr-dev/payload-automation version", + "Plugin Configuration": "Verify automationPlugin() is called with correct collections array", + "Database Collections": "Confirm 'workflows' and 'workflow-runs' collections exist", + "Hook Registration": "Check if afterChange hooks are actually registered on orders collection", + "Workflow Status": "Verify workflow document has _status: 'published'", + "Workflow Structure": "Confirm triggers array and steps array are populated", + "Order Collection": "Verify orders collection exists and is configured in plugin", + "PayloadCMS Version": "Check if you're using compatible Payload version", + "Environment": "Development vs Production database differences" +} + +console.log('\n๐Ÿ“‹ Debugging Checklist for Your Environment:') +Object.entries(debugChecklist).forEach(([check, description], i) => { + console.log(`${i + 1}. ${check}: ${description}`) +}) + +console.log('\n๐Ÿ” Specific Things to Check in YOUR Environment:') + +console.log('\n1. Plugin Configuration (payload.config.ts):') +console.log(` automationPlugin({ + collections: ['orders', 'users', 'products'], // <- Must include 'orders' + // ... other config + })`) + +console.log('\n2. Database Query (run this in your environment):') +console.log(` const workflows = await payload.find({ + collection: 'workflows', + depth: 2 + }) + console.log('Found workflows:', workflows.docs.length) + console.log('Workflow details:', JSON.stringify(workflows.docs, null, 2))`) + +console.log('\n3. Hook Registration Check:') +console.log(` const orderCollection = payload.collections.orders + console.log('afterChange hooks:', orderCollection.config.hooks?.afterChange?.length)`) + +console.log('\n4. Manual Hook Trigger Test:') +console.log(` // Manually call the executor method + const executor = // get executor instance somehow + await executor.executeTriggeredWorkflows('orders', 'update', updatedDoc, previousDoc, req)`) + +console.log('\n5. Most Likely Issues:') +console.log(' - Plugin not configured with "orders" in collections array') +console.log(' - Workflow is in draft status (not published)') +console.log(' - Database connection issue (different DB in dev vs prod)') +console.log(' - PayloadCMS version compatibility issue') +console.log(' - Hook execution order (automation hook not running last)') + +console.log('\n๐Ÿ’ก Quick Test - Add this to your order update code:') +console.log(` console.log('๐Ÿ” DEBUG: About to update order') + const result = await payload.update({ ... }) + console.log('๐Ÿ” DEBUG: Order updated, hooks should have fired') + + // Check immediately after + const runs = await payload.find({ collection: 'workflow-runs' }) + console.log('๐Ÿ” DEBUG: Workflow runs after update:', runs.docs.length)`) + +process.exit(0) \ No newline at end of file diff --git a/debug-workflow-execution.js b/debug-workflow-execution.js new file mode 100644 index 0000000..f29f13c --- /dev/null +++ b/debug-workflow-execution.js @@ -0,0 +1,210 @@ +// Enhanced debugging script for workflow execution issues +const { getPayload } = require('payload') +const { JSONPath } = require('jsonpath-plus') + +async function debugWorkflowExecution() { + const payload = await getPayload({ + config: require('./dev/payload.config.ts').default + }) + + console.log('๐Ÿ” === WORKFLOW EXECUTION DEBUGGING ===') + + // Step 1: Verify workflow exists and has correct structure + console.log('\n๐Ÿ“‹ Step 1: Finding workflows...') + const workflows = await payload.find({ + collection: 'workflows', + depth: 2, + limit: 100 + }) + + console.log(`Found ${workflows.docs.length} workflows:`) + + for (const workflow of workflows.docs) { + console.log(`\n Workflow: "${workflow.name}" (ID: ${workflow.id})`) + console.log(` Enabled: ${workflow.enabled !== false}`) + console.log(` Triggers: ${JSON.stringify(workflow.triggers, null, 4)}`) + console.log(` Steps: ${JSON.stringify(workflow.steps, null, 4)}`) + } + + // Step 2: Create test order and simulate the trigger context + console.log('\n๐Ÿ“ฆ Step 2: Creating test order...') + + const testOrder = await payload.create({ + collection: 'orders', + data: { + orderName: 'Debug Test Order - ' + Date.now(), + status: 'Unpaid', + customerEmail: 'debug@example.com', + totalPrice: 1500, + items: [ + { + name: 'Debug Item', + quantity: 1, + price: 1500 + } + ] + } + }) + + console.log(`Created test order: ${testOrder.id} with status: "${testOrder.status}"`) + + // Step 3: Test JSONPath condition evaluation directly + console.log('\n๐Ÿงช Step 3: Testing JSONPath condition evaluation...') + + // Simulate the execution context that would be created during hook execution + const simulatedContext = { + steps: {}, + trigger: { + type: 'collection', + collection: 'orders', + doc: { ...testOrder, status: 'Paid' }, // Simulating the updated status + operation: 'update', + previousDoc: testOrder, // Original order with 'Unpaid' status + } + } + + console.log('Simulated context:') + console.log(' - Trigger type:', simulatedContext.trigger.type) + console.log(' - Collection:', simulatedContext.trigger.collection) + console.log(' - Doc status:', simulatedContext.trigger.doc.status) + console.log(' - Previous doc status:', simulatedContext.trigger.previousDoc.status) + + // Test the condition used in workflow + const condition = '$.doc.status == "Paid"' + console.log(`\nTesting condition: ${condition}`) + + try { + // Test left side JSONPath resolution + const leftResult = JSONPath({ + json: simulatedContext, + path: '$.trigger.doc.status', + wrap: false + }) + console.log(` - Left side ($.trigger.doc.status): ${JSON.stringify(leftResult)} (type: ${typeof leftResult})`) + + // Test the comparison manually + const comparisonMatch = condition.match(/^(.+?)\s*(==|!=|>|<|>=|<=)\s*(.+)$/) + if (comparisonMatch) { + const [, leftExpr, operator, rightExpr] = comparisonMatch + console.log(` - Left expression: "${leftExpr.trim()}"`) + console.log(` - Operator: "${operator}"`) + console.log(` - Right expression: "${rightExpr.trim()}"`) + + // Parse right side (remove quotes if it's a string literal) + let rightValue = rightExpr.trim() + if (rightValue.startsWith('"') && rightValue.endsWith('"')) { + rightValue = rightValue.slice(1, -1) + } + console.log(` - Right value: "${rightValue}" (type: ${typeof rightValue})`) + + const conditionResult = leftResult === rightValue + console.log(` - Condition result: ${conditionResult} (${leftResult} === ${rightValue})`) + } + + } catch (error) { + console.error('โŒ JSONPath evaluation failed:', error.message) + } + + // Step 4: Test workflow trigger matching logic + console.log('\n๐ŸŽฏ Step 4: Testing trigger matching logic...') + + for (const workflow of workflows.docs) { + console.log(`\nChecking workflow: "${workflow.name}"`) + + const triggers = workflow.triggers + if (!triggers || !Array.isArray(triggers)) { + console.log(' โŒ No triggers found') + continue + } + + for (const trigger of triggers) { + console.log(` Trigger details:`) + console.log(` - Type: ${trigger.type}`) + console.log(` - Collection: ${trigger.collection}`) + console.log(` - CollectionSlug: ${trigger.collectionSlug}`) + console.log(` - Operation: ${trigger.operation}`) + console.log(` - Condition: ${trigger.condition}`) + + // Check basic matching criteria + const typeMatch = trigger.type === 'collection-trigger' + const collectionMatch = trigger.collection === 'orders' || trigger.collectionSlug === 'orders' + const operationMatch = trigger.operation === 'update' + + console.log(` - Type match: ${typeMatch}`) + console.log(` - Collection match: ${collectionMatch}`) + console.log(` - Operation match: ${operationMatch}`) + + if (typeMatch && collectionMatch && operationMatch) { + console.log(` โœ… Basic trigger criteria match!`) + + if (trigger.condition) { + console.log(` Testing condition: ${trigger.condition}`) + // Note: We'd need to call the actual evaluateCondition method here + // but we're simulating the logic + } else { + console.log(` โœ… No condition required - this trigger should fire!`) + } + } else { + console.log(` โŒ Basic trigger criteria don't match`) + } + } + } + + // Step 5: Update order and trace hook execution + console.log('\n๐Ÿ”„ Step 5: Updating order status to trigger workflow...') + + console.log('Before update - checking existing workflow runs:') + const beforeRuns = await payload.find({ + collection: 'workflow-runs' + }) + console.log(` Existing workflow runs: ${beforeRuns.docs.length}`) + + console.log('\nUpdating order status to "Paid"...') + const updatedOrder = await payload.update({ + collection: 'orders', + id: testOrder.id, + data: { + status: 'Paid' + } + }) + + console.log(`Order updated successfully. New status: "${updatedOrder.status}"`) + + // Wait a moment for async processing + await new Promise(resolve => setTimeout(resolve, 3000)) + + console.log('\nAfter update - checking for new workflow runs:') + const afterRuns = await payload.find({ + collection: 'workflow-runs' + }) + console.log(` Total workflow runs: ${afterRuns.docs.length}`) + console.log(` New runs created: ${afterRuns.docs.length - beforeRuns.docs.length}`) + + if (afterRuns.docs.length > beforeRuns.docs.length) { + const newRuns = afterRuns.docs.slice(0, afterRuns.docs.length - beforeRuns.docs.length) + for (const run of newRuns) { + console.log(` - Run ID: ${run.id}`) + console.log(` - Workflow: ${run.workflow}`) + console.log(` - Status: ${run.status}`) + console.log(` - Context: ${JSON.stringify(run.context, null, 2)}`) + } + } + + // Step 6: Check job queue + console.log('\nโš™๏ธ Step 6: Checking job queue...') + const jobs = await payload.find({ + collection: 'payload-jobs', + sort: '-createdAt', + limit: 10 + }) + + console.log(`Recent jobs in queue: ${jobs.docs.length}`) + for (const job of jobs.docs.slice(0, 5)) { + console.log(` - Job ${job.id}: ${job.taskSlug} (${job.processingError ? 'ERROR' : 'OK'})`) + } + + console.log('\nโœจ Debugging complete!') + process.exit(0) +} + +debugWorkflowExecution().catch(console.error) \ No newline at end of file diff --git a/debug-workflow-executor-patch.js b/debug-workflow-executor-patch.js new file mode 100644 index 0000000..2011747 --- /dev/null +++ b/debug-workflow-executor-patch.js @@ -0,0 +1,177 @@ +// Enhanced debugging patch for workflow executor +// This temporarily patches the workflow executor to add comprehensive logging + +import { getPayload } from 'payload' + +async function patchAndTestWorkflow() { + const payload = await getPayload({ + config: (await import('./dev/payload.config.ts')).default + }) + + console.log('๐Ÿ”ง === COMPREHENSIVE WORKFLOW DEBUGGING ===') + + // Step 1: Check workflow collection structure and versioning + console.log('\n๐Ÿ“‹ Step 1: Analyzing workflow collection configuration...') + + const workflowCollection = payload.collections.workflows + console.log('Workflow collection config:') + console.log(' - Slug:', workflowCollection.config.slug) + console.log(' - Versions enabled:', !!workflowCollection.config.versions) + console.log(' - Drafts enabled:', !!workflowCollection.config.versions?.drafts) + + // Step 2: Test different query approaches for workflows + console.log('\n๐Ÿ” Step 2: Testing workflow queries...') + + // Query 1: Default query (what the plugin currently uses) + console.log('Query 1: Default query (no status filter)') + try { + const workflows1 = await payload.find({ + collection: 'workflows', + depth: 2, + limit: 100 + }) + console.log(` - Found: ${workflows1.docs.length} workflows`) + for (const wf of workflows1.docs) { + console.log(` - "${wf.name}" (ID: ${wf.id}) Status: ${wf._status || 'no-status'}`) + } + } catch (error) { + console.log(` - Error: ${error.message}`) + } + + // Query 2: Only published workflows + console.log('\nQuery 2: Only published workflows') + try { + const workflows2 = await payload.find({ + collection: 'workflows', + depth: 2, + limit: 100, + where: { + _status: { + equals: 'published' + } + } + }) + console.log(` - Found: ${workflows2.docs.length} published workflows`) + for (const wf of workflows2.docs) { + console.log(` - "${wf.name}" (ID: ${wf.id}) Status: ${wf._status}`) + console.log(` Triggers: ${JSON.stringify(wf.triggers, null, 2)}`) + } + } catch (error) { + console.log(` - Error: ${error.message}`) + } + + // Query 3: All workflows with explicit status + console.log('\nQuery 3: All workflows with status field') + try { + const workflows3 = await payload.find({ + collection: 'workflows', + depth: 2, + limit: 100, + where: { + _status: { + exists: true + } + } + }) + console.log(` - Found: ${workflows3.docs.length} workflows with status`) + for (const wf of workflows3.docs) { + console.log(` - "${wf.name}" Status: ${wf._status}`) + } + } catch (error) { + console.log(` - Error: ${error.message}`) + } + + // Step 3: Create a test order and manually trigger the evaluation + console.log('\n๐Ÿ“ฆ Step 3: Creating test order...') + + const testOrder = await payload.create({ + collection: 'orders', + data: { + orderName: 'Debug Comprehensive Test - ' + Date.now(), + status: 'Unpaid', + customerEmail: 'debug@example.com', + totalPrice: 1000, + items: [{ + name: 'Debug Item', + quantity: 1, + price: 1000 + }] + } + }) + + console.log(`Created order: ${testOrder.id} with status: ${testOrder.status}`) + + // Step 4: Test the WorkflowExecutor.executeTriggeredWorkflows method directly + console.log('\n๐ŸŽฏ Step 4: Testing executeTriggeredWorkflows directly...') + + // Access the workflow executor (this might require accessing internal plugin state) + // For now, let's simulate what should happen + + console.log('Simulating executeTriggeredWorkflows call...') + console.log(' - Collection: orders') + console.log(' - Operation: update') + console.log(' - Doc: { ...order, status: "Paid" }') + console.log(' - PreviousDoc:', JSON.stringify(testOrder, null, 2)) + + // Step 5: Update the order and capture all logs + console.log('\n๐Ÿ”„ Step 5: Updating order with comprehensive logging...') + + // First, let's check what hooks are actually registered + const orderCollection = payload.collections.orders + console.log('Order collection hooks:') + console.log(' - afterChange hooks:', orderCollection.config.hooks?.afterChange?.length || 0) + + // Count current workflow runs before + const beforeRuns = await payload.find({ collection: 'workflow-runs' }) + console.log(`Current workflow runs: ${beforeRuns.docs.length}`) + + // Update the order + console.log('\nUpdating order status to "Paid"...') + const updatedOrder = await payload.update({ + collection: 'orders', + id: testOrder.id, + data: { status: 'Paid' } + }) + + console.log(`Order updated: ${updatedOrder.status}`) + + // Wait and check for workflow runs + console.log('Waiting 5 seconds for async processing...') + await new Promise(resolve => setTimeout(resolve, 5000)) + + const afterRuns = await payload.find({ collection: 'workflow-runs' }) + console.log(`Workflow runs after: ${afterRuns.docs.length}`) + console.log(`New runs created: ${afterRuns.docs.length - beforeRuns.docs.length}`) + + if (afterRuns.docs.length > beforeRuns.docs.length) { + console.log('โœ… New workflow runs found!') + const newRuns = afterRuns.docs.slice(0, afterRuns.docs.length - beforeRuns.docs.length) + for (const run of newRuns) { + console.log(` - Run ${run.id}: ${run.status}`) + } + } else { + console.log('โŒ No new workflow runs created') + + // Additional debugging + console.log('\n๐Ÿ•ต๏ธ Deep debugging - checking plugin state...') + + // Check if the plugin is actually loaded + console.log('Available collections:', Object.keys(payload.collections)) + + // Check for recent jobs + const recentJobs = await payload.find({ + collection: 'payload-jobs', + sort: '-createdAt', + limit: 5 + }) + console.log(`Recent jobs: ${recentJobs.docs.length}`) + for (const job of recentJobs.docs) { + console.log(` - ${job.taskSlug} (${job.processingError ? 'ERROR' : 'OK'})`) + } + } + + console.log('\nโœจ Comprehensive debugging complete!') + process.exit(0) +} + +patchAndTestWorkflow().catch(console.error) \ No newline at end of file diff --git a/src/plugin/index.ts b/src/plugin/index.ts index 8046424..25e76b1 100644 --- a/src/plugin/index.ts +++ b/src/plugin/index.ts @@ -27,8 +27,6 @@ const applyCollectionsConfig = (pluginOptions: WorkflowsPlugin ) } -// Track if hooks have been initialized to prevent double registration -let hooksInitialized = false export const workflowsPlugin = (pluginOptions: WorkflowsPluginConfig) => @@ -65,13 +63,7 @@ export const workflowsPlugin = // Set up onInit to register collection hooks and initialize features const incomingOnInit = config.onInit config.onInit = async (payload) => { - configLogger.info(`onInit called - hooks already initialized: ${hooksInitialized}, collections: ${Object.keys(payload.collections).length}`) - - // Prevent double initialization in dev mode - if (hooksInitialized) { - configLogger.warn('Hooks already initialized, skipping to prevent duplicate registration') - return - } + configLogger.info(`onInit called - collections: ${Object.keys(payload.collections).length}`) // Execute any existing onInit functions first if (incomingOnInit) { @@ -107,7 +99,6 @@ export const workflowsPlugin = await registerCronJobs(payload, logger) logger.info('Plugin initialized successfully - all hooks registered') - hooksInitialized = true } return config diff --git a/src/plugin/init-collection-hooks.ts b/src/plugin/init-collection-hooks.ts index 80dc3a5..4659e9e 100644 --- a/src/plugin/init-collection-hooks.ts +++ b/src/plugin/init-collection-hooks.ts @@ -39,19 +39,37 @@ export function initCollectionHooks(pluginOptions: WorkflowsPl collection.config.hooks.afterChange = collection.config.hooks.afterChange || [] collection.config.hooks.afterChange.push(async (change) => { const operation = change.operation as 'create' | 'update' - logger.debug({ + logger.info({ slug: change.collection.slug, operation, - }, 'Collection hook triggered') + docId: change.doc?.id, + previousDocId: change.previousDoc?.id, + }, 'AUTOMATION PLUGIN: Collection hook triggered') - // Execute workflows for this trigger - await executor.executeTriggeredWorkflows( - change.collection.slug, - operation, - change.doc, - change.previousDoc, - change.req - ) + try { + // Execute workflows for this trigger + await executor.executeTriggeredWorkflows( + change.collection.slug, + operation, + change.doc, + change.previousDoc, + change.req + ) + logger.info({ + slug: change.collection.slug, + operation, + docId: change.doc?.id + }, 'AUTOMATION PLUGIN: executeTriggeredWorkflows completed successfully') + } catch (error) { + logger.error({ + slug: change.collection.slug, + operation, + docId: change.doc?.id, + error: error instanceof Error ? error.message : 'Unknown error', + stack: error instanceof Error ? error.stack : undefined + }, 'AUTOMATION PLUGIN: executeTriggeredWorkflows failed') + // Don't re-throw to avoid breaking other hooks + } }) } diff --git a/test-jsonpath-condition.js b/test-jsonpath-condition.js new file mode 100644 index 0000000..00758ac --- /dev/null +++ b/test-jsonpath-condition.js @@ -0,0 +1,115 @@ +// Isolated JSONPath condition testing +import { JSONPath } from 'jsonpath-plus' + +function testJSONPathCondition() { + console.log('๐Ÿงช Testing JSONPath condition evaluation in isolation') + + // Simulate the exact context structure from workflow execution + const testContext = { + steps: {}, + trigger: { + type: 'collection', + collection: 'orders', + doc: { + id: '12345', + orderName: 'Test Order', + status: 'Paid', // This is the updated status + customerEmail: 'test@example.com', + totalPrice: 2500 + }, + operation: 'update', + previousDoc: { + id: '12345', + orderName: 'Test Order', + status: 'Unpaid', // This was the previous status + customerEmail: 'test@example.com', + totalPrice: 2500 + } + } + } + + console.log('Test context:') + console.log(' - trigger.doc.status:', testContext.trigger.doc.status) + console.log(' - trigger.previousDoc.status:', testContext.trigger.previousDoc.status) + + // Test different JSONPath expressions + const testCases = [ + '$.trigger.doc.status', + '$.doc.status', // This is what your condition uses but might be wrong! + '$.trigger.doc.status == "Paid"', + '$.trigger.doc.status == "Unpaid"' + ] + + console.log('\n๐Ÿ“‹ Testing JSONPath expressions:') + + for (const expression of testCases) { + try { + const result = JSONPath({ + json: testContext, + path: expression, + wrap: false + }) + + console.log(` โœ… ${expression} => ${JSON.stringify(result)} (${typeof result})`) + } catch (error) { + console.log(` โŒ ${expression} => ERROR: ${error.message}`) + } + } + + // Test comparison logic manually + console.log('\n๐Ÿ” Testing comparison logic:') + + const condition = '$.doc.status == "Paid"' // Your original condition + const correctCondition = '$.trigger.doc.status == "Paid"' // Likely correct path + + console.log(`\nTesting: ${condition}`) + try { + const leftResult = JSONPath({ + json: testContext, + path: '$.doc.status', + wrap: false + }) + console.log(` - Left side result: ${JSON.stringify(leftResult)}`) + console.log(` - Is undefined/null? ${leftResult === undefined || leftResult === null}`) + console.log(` - Comparison result: ${leftResult === 'Paid'}`) + } catch (error) { + console.log(` - Error: ${error.message}`) + } + + console.log(`\nTesting: ${correctCondition}`) + try { + const leftResult = JSONPath({ + json: testContext, + path: '$.trigger.doc.status', + wrap: false + }) + console.log(` - Left side result: ${JSON.stringify(leftResult)}`) + console.log(` - Comparison result: ${leftResult === 'Paid'}`) + } catch (error) { + console.log(` - Error: ${error.message}`) + } + + // Test regex parsing + console.log('\n๐Ÿ“ Testing regex parsing:') + const testConditions = [ + '$.trigger.doc.status == "Paid"', + '$.doc.status == "Paid"', + '$.trigger.doc.status=="Paid"', // No spaces + "$.trigger.doc.status == 'Paid'" // Single quotes + ] + + for (const cond of testConditions) { + const comparisonMatch = cond.match(/^(.+?)\s*(==|!=|>|<|>=|<=)\s*(.+)$/) + if (comparisonMatch) { + const [, leftExpr, operator, rightExpr] = comparisonMatch + console.log(` โœ… ${cond}`) + console.log(` - Left: "${leftExpr.trim()}"`) + console.log(` - Operator: "${operator}"`) + console.log(` - Right: "${rightExpr.trim()}"`) + } else { + console.log(` โŒ ${cond} - No regex match`) + } + } +} + +testJSONPathCondition() \ No newline at end of file diff --git a/test-published-workflows.js b/test-published-workflows.js new file mode 100644 index 0000000..0a7db78 --- /dev/null +++ b/test-published-workflows.js @@ -0,0 +1,44 @@ +// Test script to verify published workflow filtering +console.log('๐Ÿ” Testing published workflow filtering...') + +// This will be run from the dev environment +// Start the dev server first: pnpm dev +// Then in another terminal: node test-published-workflows.js + +const testData = { + // Simulate what the workflow executor should find + allWorkflows: [ + { + id: 1, + name: 'Draft Workflow', + _status: 'draft', + triggers: [{ type: 'collection-trigger', collectionSlug: 'orders', operation: 'update' }] + }, + { + id: 2, + name: 'Published Workflow', + _status: 'published', + triggers: [{ type: 'collection-trigger', collectionSlug: 'orders', operation: 'update' }] + } + ] +} + +// Test filtering logic +const publishedOnly = testData.allWorkflows.filter(wf => wf._status === 'published') + +console.log('All workflows:', testData.allWorkflows.length) +console.log('Published workflows:', publishedOnly.length) +console.log('Published workflow names:', publishedOnly.map(wf => wf.name)) + +console.log('\nโœ… The published status filter should work!') +console.log('๐Ÿ’ก Make sure your workflow has _status: "published" in the database') + +// Instructions for manual verification +console.log('\n๐Ÿ“‹ Manual verification steps:') +console.log('1. Start dev server: pnpm dev') +console.log('2. Go to http://localhost:3000/admin/collections/workflows') +console.log('3. Find your workflow and ensure it shows as "Published" (not "Draft")') +console.log('4. If it shows as "Draft", click it and click "Publish"') +console.log('5. Then test your order status change again') + +process.exit(0) \ No newline at end of file diff --git a/test-workflow-creation.js b/test-workflow-creation.js new file mode 100644 index 0000000..b69082b --- /dev/null +++ b/test-workflow-creation.js @@ -0,0 +1,113 @@ +// Test script to create workflow with correct v0.0.15 schema structure +const { getPayload } = require('payload') + +async function testWorkflowCreation() { + const payload = await getPayload({ + config: require('./dev/payload.config.ts').default + }) + + console.log('๐Ÿš€ Creating workflow with v0.0.15 schema...') + + try { + const workflow = await payload.create({ + collection: 'workflows', + data: { + name: 'Test Order Status Workflow v0.0.15', + description: 'Test workflow that triggers when order status changes to Paid', + enabled: true, + triggers: [ + { + type: 'collection-trigger', + collectionSlug: 'orders', + operation: 'update', + // v0.0.15 uses 'condition' (singular) with JSONPath expressions + // instead of 'conditions' array + condition: '$.doc.status == "Paid"' + } + ], + steps: [ + { + // v0.0.15 uses 'step' field instead of 'type' + step: 'uppercaseText', + name: 'Test Uppercase Step', + // v0.0.15 uses 'input' (singular) instead of 'inputs' + input: { + inputText: 'Order {{$.trigger.doc.orderName}} has been paid!' + } + } + ] + } + }) + + console.log('โœ… Workflow created successfully!') + console.log('๐Ÿ“‹ Workflow details:') + console.log(' - ID:', workflow.id) + console.log(' - Name:', workflow.name) + console.log(' - Triggers:', JSON.stringify(workflow.triggers, null, 2)) + console.log(' - Steps:', JSON.stringify(workflow.steps, null, 2)) + + // Now test with an order update + console.log('\n๐Ÿ”„ Testing order status change...') + + // First create a test order + const order = await payload.create({ + collection: 'orders', + data: { + orderName: 'Test Order - ' + Date.now(), + status: 'Unpaid', + customerEmail: 'test@example.com', + totalPrice: 2500, + items: [ + { + name: 'Test Item', + quantity: 1, + price: 2500 + } + ] + } + }) + + console.log('๐Ÿ“ฆ Test order created:', order.id) + + // Update order status to trigger workflow + const updatedOrder = await payload.update({ + collection: 'orders', + id: order.id, + data: { + status: 'Paid' + } + }) + + console.log('๐Ÿ’ฐ Order status updated to:', updatedOrder.status) + + // Wait a moment for async workflow execution + await new Promise(resolve => setTimeout(resolve, 2000)) + + // Check for workflow runs + const workflowRuns = await payload.find({ + collection: 'workflow-runs', + where: { + workflow: { + equals: workflow.id + } + } + }) + + console.log(`\n๐Ÿ“Š Workflow runs found: ${workflowRuns.docs.length}`) + + if (workflowRuns.docs.length > 0) { + const run = workflowRuns.docs[0] + console.log(' - Run ID:', run.id) + console.log(' - Status:', run.status) + console.log(' - Context:', JSON.stringify(run.context, null, 2)) + } + + } catch (error) { + console.error('โŒ Error:', error.message) + console.error('Stack:', error.stack) + } + + process.exit(0) +} + +testWorkflowCreation() \ No newline at end of file