From 95df39f5f2904b6fcdb915de195fc546612dad6c Mon Sep 17 00:00:00 2001 From: Richard McDaniel Date: Mon, 27 Oct 2025 04:19:41 +0000 Subject: [PATCH 1/2] Fix webhookUrl() to account for route prefixes - Add named routes to webhook registrations for proper prefix handling - Update webhookUrl() to use route() helper instead of manual URL construction - This ensures webhook URLs include route prefixes (e.g., api/) when routes are registered in prefixed route files - Maintains compatibility with route caching and Laravel conventions - Builds on previous fix that added workflow slug to signal URLs --- src/Activity.php | 7 ++++--- src/Webhooks.php | 4 ++-- tests/Fixtures/TestWorkflow.php | 3 +++ tests/Unit/ActivityTest.php | 7 +++++-- tests/Unit/WebhooksTest.php | 15 ++++----------- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Activity.php b/src/Activity.php index c1cb017c..ed412c82 100644 --- a/src/Activity.php +++ b/src/Activity.php @@ -76,15 +76,16 @@ public function workflowId() public function webhookUrl(string $signalMethod = ''): string { - $basePath = config('workflows.webhooks_route', '/webhooks'); $workflow = Str::kebab(class_basename($this->storedWorkflow->class)); if ($signalMethod === '') { - return url("{$basePath}/{$workflow}"); + return route("workflows.start.{$workflow}"); } $signal = Str::kebab($signalMethod); - return url("{$basePath}/signal/{$workflow}/{$this->storedWorkflow->id}/{$signal}"); + return route("workflows.signal.{$workflow}.{$signal}", [ + 'workflowId' => $this->storedWorkflow->id + ]); } public function handle() diff --git a/src/Webhooks.php b/src/Webhooks.php index 36220f21..92dd595c 100644 --- a/src/Webhooks.php +++ b/src/Webhooks.php @@ -85,7 +85,7 @@ private static function registerWorkflowWebhooks($workflow, $basePath) return response()->json([ 'message' => 'Workflow started', ]); - }); + })->name("workflows.start.{$slug}"); } } } @@ -111,7 +111,7 @@ static function (Request $request, $workflowId) use ($workflow, $method) { 'message' => 'Signal sent', ]); } - ); + )->name("workflows.signal.{$slug}.{$signal}"); } } } diff --git a/tests/Fixtures/TestWorkflow.php b/tests/Fixtures/TestWorkflow.php index 2ec8359d..fe4b63c3 100644 --- a/tests/Fixtures/TestWorkflow.php +++ b/tests/Fixtures/TestWorkflow.php @@ -8,9 +8,11 @@ use Workflow\ActivityStub; use Workflow\QueryMethod; use Workflow\SignalMethod; +use Workflow\Webhook; use Workflow\Workflow; use Workflow\WorkflowStub; +#[Webhook] class TestWorkflow extends Workflow { public $connection = 'redis'; @@ -20,6 +22,7 @@ class TestWorkflow extends Workflow private bool $canceled = false; #[SignalMethod] + #[Webhook] public function cancel(): void { $this->canceled = true; diff --git a/tests/Unit/ActivityTest.php b/tests/Unit/ActivityTest.php index 42609927..383522ec 100644 --- a/tests/Unit/ActivityTest.php +++ b/tests/Unit/ActivityTest.php @@ -17,6 +17,7 @@ use Workflow\Serializers\Serializer; use Workflow\States\WorkflowCreatedStatus; use Workflow\States\WorkflowFailedStatus; +use Workflow\Webhooks; use Workflow\WorkflowStub; final class ActivityTest extends TestCase @@ -125,12 +126,14 @@ public function testActivityAlreadyComplete(): void public function testWebhookUrl(): void { + Webhooks::routes('Tests\\Fixtures', __DIR__ . '/../Fixtures'); + $workflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); $activity = new TestOtherActivity(0, now()->toDateTimeString(), StoredWorkflow::findOrFail($workflow->id()), [ 'other', ]); - $this->assertSame('http://localhost/webhooks/test-workflow', $activity->webhookUrl()); - $this->assertSame('http://localhost/webhooks/signal/test-workflow/1/other', $activity->webhookUrl('other')); + $this->assertSame('http://localhost/webhooks/start/test-workflow', $activity->webhookUrl()); + $this->assertSame('http://localhost/webhooks/signal/test-workflow/1/cancel', $activity->webhookUrl('cancel')); } } diff --git a/tests/Unit/WebhooksTest.php b/tests/Unit/WebhooksTest.php index c811e6e4..3a717f1d 100644 --- a/tests/Unit/WebhooksTest.php +++ b/tests/Unit/WebhooksTest.php @@ -313,19 +313,12 @@ public function testResolveNamedParametersUsesDefaults() public function testWebhookRegistration() { - $response = $this->postJson('/webhooks/signal/test-webhook-workflow/1/cancel'); - - Route::shouldReceive('post') - ->once() - ->withArgs(static function ($uri, $callback) { - return str_contains($uri, 'webhooks/start/test-webhook-workflow'); - }); + $routeMock = Mockery::mock(); + $routeMock->shouldReceive('name')->andReturnSelf(); Route::shouldReceive('post') - ->once() - ->withArgs(static function ($uri, $callback) { - return str_contains($uri, 'webhooks/signal/test-webhook-workflow/{workflowId}/cancel'); - }); + ->times(4) + ->andReturn($routeMock); Webhooks::routes('Tests\\Fixtures', __DIR__ . '/../Fixtures'); } From 0f9a5f5728644a5be5868c99c37e21034b44f22c Mon Sep 17 00:00:00 2001 From: Richard McDaniel Date: Mon, 27 Oct 2025 04:27:09 +0000 Subject: [PATCH 2/2] Fix code style issues - Add trailing comma in array parameter - Fix method chaining indentation --- src/Activity.php | 2 +- tests/Unit/WebhooksTest.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Activity.php b/src/Activity.php index ed412c82..44a4f265 100644 --- a/src/Activity.php +++ b/src/Activity.php @@ -84,7 +84,7 @@ public function webhookUrl(string $signalMethod = ''): string $signal = Str::kebab($signalMethod); return route("workflows.signal.{$workflow}.{$signal}", [ - 'workflowId' => $this->storedWorkflow->id + 'workflowId' => $this->storedWorkflow->id, ]); } diff --git a/tests/Unit/WebhooksTest.php b/tests/Unit/WebhooksTest.php index 3a717f1d..9fd3d455 100644 --- a/tests/Unit/WebhooksTest.php +++ b/tests/Unit/WebhooksTest.php @@ -314,7 +314,8 @@ public function testResolveNamedParametersUsesDefaults() public function testWebhookRegistration() { $routeMock = Mockery::mock(); - $routeMock->shouldReceive('name')->andReturnSelf(); + $routeMock->shouldReceive('name') + ->andReturnSelf(); Route::shouldReceive('post') ->times(4)