|
76208
|
1908
|
26
|
2026-04-24T07:36:37.117643+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016197117_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59574467,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.60538566,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61269945,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
482359671864130799
|
8408970457747008282
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76239
|
1908
|
42
|
2026-04-24T07:38:01.133389+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016281133_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pushed 1 commit to origin/JY-20157-AJ-report-not-s Pushed 1 commit to origin/JY-20157-AJ-report-not-send-notification
text/html
text/html
text/html
View pull request
2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Pushed 1 commit to origin/JY-20157-AJ-report-not-send-notification","depth":3,"bounds":{"left":0.8753325,"top":0.82521945,"width":0.11037234,"height":0.027134877},"value":"Pushed 1 commit to origin/JY-20157-AJ-report-not-send-notification","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.82521945,"width":0.103390954,"height":0.027134877},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"View pull request","depth":2,"bounds":{"left":0.8753325,"top":0.8579409,"width":0.03523936,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2 files committed","depth":2,"bounds":{"left":0.8753325,"top":0.89944136,"width":0.100398935,"height":0.013567438},"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"bounds":{"left":0.8753325,"top":0.915403,"width":0.11037234,"height":0.027134877},"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.915403,"width":0.09507979,"height":0.027134877},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59574467,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.60538566,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61269945,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.0,"width":0.34375,"height":1.0},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.30851063,"top":0.05027933,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.31948137,"top":0.05027933,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.328125,"top":0.05027933,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.33676863,"top":0.05027933,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.34541222,"top":0.05027933,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2823365913049337602
|
8408970457747008282
|
app_switch
|
accessibility
|
NULL
|
Pushed 1 commit to origin/JY-20157-AJ-report-not-s Pushed 1 commit to origin/JY-20157-AJ-report-not-send-notification
text/html
text/html
text/html
View pull request
2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76795
|
1927
|
3
|
2026-04-24T08:26:22.359847+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019182359_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8115828204200959479
|
8408970457747008282
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76794
|
|
76796
|
1928
|
2
|
2026-04-24T08:26:22.361872+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019182361_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.08510638,"height":0.025538707},"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.63796544,"top":0.12529927,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6476064,"top":0.123703115,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.6549202,"top":0.123703115,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.12210695,"width":0.34375,"height":0.87789303},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8115828204200959479
|
8408970457747008282
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76874
|
1929
|
6
|
2026-04-24T08:31:04.180629+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019464180_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
2249107635929059023
|
8408970457746877208
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76872
|
|
76875
|
1930
|
6
|
2026-04-24T08:31:04.277882+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019464277_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.08510638,"height":0.025538707},"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8400931,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"bounds":{"left":0.85538566,"top":0.019952115,"width":0.06017287,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.5319149,"top":0.19952115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5415558,"top":0.19792499,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.54886967,"top":0.19792499,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.05586592,"width":0.34375,"height":0.94413406},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.74202126,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.75398934,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7613032,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
2249107635929059023
|
8408970457746877208
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
75763
|
1889
|
4
|
2026-04-24T06:47:39.949525+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777013259949_m1.jpg...
|
PhpStorm
|
faVsco.js – laravel.log
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1144826565952075873
|
8408970389027400600
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
75761
|
|
75764
|
1890
|
4
|
2026-04-24T06:47:39.949543+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777013259949_m2.jpg...
|
PhpStorm
|
faVsco.js – laravel.log
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59574467,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.60538566,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61269945,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.3200319,"width":0.34375,"height":0.6799681},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"bounds":{"left":0.63863033,"top":0.09736632,"width":0.34973404,"height":0.8818835},"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1144826565952075873
|
8408970389027400600
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
75762
|
|
75765
|
1890
|
5
|
2026-04-24T06:48:10.536199+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777013290536_m2.jpg...
|
PhpStorm
|
faVsco.js – laravel.log
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59574467,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.60538566,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61269945,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.3200319,"width":0.34375,"height":0.6799681},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"bounds":{"left":0.63863033,"top":0.09736632,"width":0.34973404,"height":0.8818835},"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1144826565952075873
|
8408970389027400600
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
75766
|
1889
|
5
|
2026-04-24T06:48:11.053449+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777013291053_m1.jpg...
|
PhpStorm
|
faVsco.js – laravel.log
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1144826565952075873
|
8408970389027400600
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
75769
|
1889
|
7
|
2026-04-24T06:48:30.054322+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777013310054_m1.jpg...
|
PhpStorm
|
faVsco.js – laravel.log
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1144826565952075873
|
8408970389027400600
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
75770
|
1890
|
7
|
2026-04-24T06:48:29.955831+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777013309955_m2.jpg...
|
PhpStorm
|
faVsco.js – laravel.log
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59574467,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.60538566,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61269945,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.3200319,"width":0.34375,"height":0.6799681},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"bounds":{"left":0.63863033,"top":0.09736632,"width":0.34973404,"height":0.8818835},"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1144826565952075873
|
8408970389027400600
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
52538
|
1137
|
23
|
2026-04-20T07:21:26.039285+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776669686039_m2.jpg...
|
PhpStorm
|
faVsco.js – console [EU]
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Laravel Idea: Generate Helper Code?
Helper Code wi Laravel Idea: Generate Helper Code?
Helper Code will help IDE to understand your Laravel app code.
text/html
text/html
text/html
Generate
Don't Show Anymore
More
The Hunspell plugin has been deprecated. If you're not writing in Hungarian, you can safely uninstall Hunspell without affecting the dictionaries for other languages.
text/html
text/html
text/html
Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
11
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Laravel Idea: Generate Helper Code?","depth":2,"bounds":{"left":0.8753325,"top":0.8172386,"width":0.100398935,"height":0.013567438},"role_description":"text"},{"role":"AXTextField","text":"Helper Code will help IDE to understand your Laravel app code.","depth":3,"bounds":{"left":0.8753325,"top":0.83320034,"width":0.11037234,"height":0.027134877},"value":"Helper Code will help IDE to understand your Laravel app code.","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.83320034,"width":0.09275266,"height":0.027134877},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Generate","depth":2,"bounds":{"left":0.8753325,"top":0.8659218,"width":0.018949468,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Don't Show Anymore","depth":2,"bounds":{"left":0.89960104,"top":0.8659218,"width":0.04288564,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"More","depth":2,"bounds":{"left":0.27027926,"top":1.0,"width":0.016289894,"height":0.0},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"The Hunspell plugin has been deprecated. If you're not writing in Hungarian, you can safely uninstall Hunspell without affecting the dictionaries for other languages.","depth":3,"bounds":{"left":0.8753325,"top":0.9074222,"width":0.11037234,"height":0.054269753},"value":"The Hunspell plugin has been deprecated. If you're not writing in Hungarian, you can safely uninstall Hunspell without affecting the dictionaries for other languages.","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.9074222,"width":0.095744684,"height":0.054269753},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.36868352,"top":0.2490024,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"11","depth":4,"bounds":{"left":0.37865692,"top":0.2490024,"width":0.008976064,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.38929522,"top":0.24740623,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.39660904,"top":0.24740623,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.40492022,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"bounds":{"left":0.41356382,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"bounds":{"left":0.4245346,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"bounds":{"left":0.4331782,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"bounds":{"left":0.4418218,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"bounds":{"left":0.45279256,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.4637633,"top":0.09896249,"width":0.024268618,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.49035904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.5013298,"top":0.09896249,"width":0.029587766,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.69913566,"top":0.09896249,"width":0.02825798,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
3161242233991905402
|
8406718657933331226
|
visual_change
|
accessibility
|
NULL
|
Laravel Idea: Generate Helper Code?
Helper Code wi Laravel Idea: Generate Helper Code?
Helper Code will help IDE to understand your Laravel app code.
text/html
text/html
text/html
Generate
Don't Show Anymore
More
The Hunspell plugin has been deprecated. If you're not writing in Hungarian, you can safely uninstall Hunspell without affecting the dictionaries for other languages.
text/html
text/html
text/html
Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
11
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification...
|
NULL
|
|
72869
|
1778
|
7
|
2026-04-23T06:20:20.846438+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-23/1776 /Users/lukas/.screenpipe/data/data/2026-04-23/1776925220846_m1.jpg...
|
PhpStorm
|
faVsco.js – UserTransformer.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20157-AJ-report-not-se Project: faVsco.js, menu
JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
12
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Http\Transformers;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Collection;
use Jiminny\Component\Sidekick\SidekickService;
use Jiminny\Exceptions\ActivityProviderException;
use Jiminny\Http\Controllers\Settings\Users\Utils\UserSetting;
use Jiminny\Models\Activity\Provider;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\JobTitle;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Notification\Messengers\MsTeams;
use Jiminny\Services\UserService;
use League\Fractal\Resource;
use League\Fractal\Resource\Item;
use League\Fractal\TransformerAbstract;
class UserTransformer extends TransformerAbstract
{
protected array $availableIncludes = [
'team',
'group',
'job',
'roles',
'permissions',
];
private Container $container;
private bool $withSelfVisibility = false;
public function __construct(?Container $container = null)
{
$this->container = $container ?? app();
}
public function withSelfVisibility(): self
{
$this->withSelfVisibility = true;
return $this;
}
/**
* @throws ActivityProviderException
*
* @return array<string, mixed>
*/
public function transform(User $user): array
{
$attributes = [
'id' => $user->getUuid(),
'name' => $user->getName(),
'firstName' => $user->getFirstName(),
'photoUrl' => $user->getPhotoUrl(),
'conferenceRecordPreference' => $user->checkConferenceRecordPreference(),
'conferenceRecordInternalPreference' => $user->checkConferenceRecordInternalPreference(),
// DO NOT USE User::isCrmRequired as it is not hydrated when fetched from ES!
'crmRequired' => $user->crm_required,
'slackFollowUp' => $user->slack_follow_up,
];
// DO NOT USE User::getId as it is not hydrated when fetched from ES!
if ($this->withSelfVisibility || (auth()->check() && auth()->user()->id === $user->id)) {
$softphoneHasVoiceCapability = $user->hasSoftphoneNumberCapabilities()
&& $user->getSoftphoneNumberCapabilities()->hasVoiceCapability()
;
$conferenceSidekickOpen = $user->getConferenceSidekickOpen();
$softphoneSidekickOpen = $user->getSoftphoneSidekickOpen();
$conferenceSidekickPopupOverridden = false;
$softphoneSidekickPopupOverridden = false;
$hasSidekickEnabled = true;
if ($user->getTeam()->hasFeature(FeatureEnum::SIDEKICK_SETTINGS)) {
$sidekickService = $this->getSidekickService();
$sidekickData = $sidekickService->getSidekickSettingsForUser($user);
$conferenceSidekickOpen = $sidekickData['conferenceSettings'];
$softphoneSidekickOpen = $sidekickData['softphoneSettings'];
$conferenceSidekickPopupOverridden = $sidekickData['conferenceSidekickPopupOverridden'];
$softphoneSidekickPopupOverridden = $sidekickData['softphoneSidekickPopupOverridden'];
$hasSidekickEnabled = $sidekickData['sidekickEnabled'];
}
$userService = $this->getUserService();
$dealInsightsPeriod = $userService->getDealInsightTimelinePeriod($user);
$dataFormatCountryCode = $userService->getDateTimeCountryCode($user);
// Attributes for the user only.
$attributes += [
'conferenceJoinReminder' => $user->conference_join_reminder,
'softphoneInboundRecordPreference' => $user->checkSoftphoneInboundRecordPreference(),
'softphoneOutboundRecordPreference' => $user->checkSoftphoneOutboundRecordPreference(),
'softphoneInboundDestination' => $user->softphone_inbound_destination,
'softphoneHasVoiceCapability' => $softphoneHasVoiceCapability,
'softphoneNumber' => $user->getSoftPhoneNumber(),
'formattedSoftphoneNumber' => $user->getFormattedSoftphoneNumberAttribute(),
'email' => $user->getEmailAddress(),
'secondaryEmail' => $user->getSecondaryEmailAddress(),
'phone' => $user->phone,
'secondaryPhone' => $user->secondary_phone,
'callerId' => $user->getCallerId(),
'countryCode' => $user->getCountryCode(),
'timezone' => $user->getTimezone()->getName(),
'language' => $user->getLanguage(),
'locales' => $this->container->get(UserRepository::class)->getUserLocales($user),
'status' => $user->getStatus(),
'hash' => $user->generateHash(),
'registrationDate' => $user->created_at ? $user->created_at->toIso8601String() : null,
'notifyLiveCoaching' => $user->notify_live_coaching,
'activityLogReminder' => $user->activity_log_reminder,
'conferenceSidekickOpen' => $conferenceSidekickOpen,
'softphoneSidekickOpen' => $softphoneSidekickOpen,
'conferenceSidekickPopupOverridden' => $conferenceSidekickPopupOverridden,
'softphoneSidekickPopupOverridden' => $softphoneSidekickPopupOverridden,
'hasSidekickEnabled' => $hasSidekickEnabled,
'activityActionItems' => $user->activity_action_items,
'syncEmail' => $user->isSyncEmailEnabled(),
'syncConference' => $user->sync_conference,
'syncDialer' => $user->shouldSyncDialer(),
'needsToConfigurePhoneNumber' => $this->container
->get('onboarding_phone_decider')
->isOnboardable($user),
'shouldShowPhoneNumberField' => $this->container
->get('onboarding_phone_decider')
->shouldShowPhoneNumberField($user),
UserSetting::DEAL_INSIGHTS_TIMELINE_PERIOD => $dealInsightsPeriod,
'countryByTimezone' => $dataFormatCountryCode,
'conferenceSlug' => $user->getConferenceSlug(),
'conferenceRecordExternalOrganizerPreference' =>
$userService->isConferenceRecordExternalOrganizerPreferenceEnabled($user),
'hasGeneratedAiReports' => $this->getAutomatedReportsRepository()->countUserReports($user) > 0,
'sendEmailWhenExportLinkIsOpened' => $userService->canSendEmailWhenExportLinkIsOpened($user),
];
if ($user->softphone_debug) {
$attributes += [
'debugSoftphone' => $user->softphone_debug, // Needed?
];
}
}
if ($user->getTeam()->getNotificationProvider() === Team::NOTIFICATION_PROVIDER_MSTEAMS) {
$socialAccountMS = $user->getSocialAccount(Team::CALENDAR_PROVIDER_OFFICE);
$state = $socialAccountMS !== null
? str_contains($socialAccountMS->auth_scope, MsTeams::SCOPE_CHAT_CREATE)
: null;
$attributes['integrations']['office'] = [
'displayName' => 'Microsoft Teams',
'apiName' => 'microsoft-teams',
'types' => ['notification'],
'state' => $state ? Provider::STATE_INSTALLED : Provider::STATE_NOT_INSTALLED,
'logo' => cdn('img/ms-teams-logo.svg'),
'installationStrategy' => 'oauth',
];
}
return $attributes;
}
public function includeTeam(User $user): Item
{
$team = $user->getTeam();
return $this->item($team, $this->getTeamTransformer());
}
public function includeGroup(User $user): ?Item
{
$group = $user->getGroup();
if ($group === null) {
return null;
}
return $this->item($group, $this->getGroupTransformer());
}
public function includeJob(User $user): ?Item
{
$job = $user->getJobTitle();
if (! $job instanceof JobTitle) {
return null;
}
return $this->item($job, $this->getJobTitleTransformer());
}
public function includeRoles(User $user): Resource\Collection
{
/** @var Collection<int, string> $roles */
$roles = $user->roles()
->where('is_visible', true)
->pluck('name')
->toArray();
return $this->collection($roles, $this->getRoleTransformer());
}
public function includePermissions(User $user): Resource\Collection
{
$permissions = $user->allPermissions();
return $this->collection($permissions, $this->getPermissionTransformer());
}
public function includeIntegrations(User $user): Item
{
return $this->item($user, $this->getIntegrationsTransformer());
}
private function getTeamTransformer(): TransformerAbstract
{
return $this->container->get(TeamTransformer::class);
}
private function getGroupTransformer(): GroupTransformer
{
return $this->container->get(GroupTransformer::class);
}
private function getIntegrationsTransformer(): IntegrationTransformer
{
return $this->container->get(IntegrationTransformer::class);
}
private function getPermissionTransformer(): PermissionTransformer
{
return $this->container->get(PermissionTransformer::class);
}
private function getRoleTransformer(): RoleTransformer
{
return $this->container->get(RoleTransformer::class);
}
private function getJobTitleTransformer(): JobTitleTransformer
{
return $this->container->get(JobTitleTransformer::class);
}
private function getSidekickService(): SidekickService
{
/** @var SidekickService */
return $this->container->get(SidekickService::class);
}
private function getUserService(): UserService
{
/** @var UserService */
return $this->container->get(UserService::class);
}
private function getAutomatedReportsRepository(): AutomatedReportsRepository
{
/** @var AutomatedReportsRepository */
return $this->container->get(AutomatedReportsRepository::class);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
36
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\DealInsights;
use Doctrine\DBAL\Connection;
use Generator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Jiminny\Component\DealInsights\Forecast\DealData;
use Jiminny\Component\DealInsights\Forecast\DealsFilter;
use Jiminny\Component\DealInsights\QueryBuilder\QueryBuilder;
use Jiminny\Component\DealInsights\QueryBuilder\Visitor\QueryBuilderVisitorInterface;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Stage;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Models;
use Jiminny\Services\Crm\IntegrationApp\DTO\Utils\UrlGeneratorInterface;
use Jiminny\Services\Crm\ProviderRegistry;
use Jiminny\Traits\RequiresUUID;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Eloquent;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class DealsRepository implements DealsRepositoryInterface
{
private Connection $connection;
private ProviderRegistry $providerRegistry;
/**
* @var QueryBuilderVisitorInterface[]
*/
private array $visitors = [];
/**
* @param QueryBuilderVisitorInterface[] $visitors
*/
public function __construct(Connection $connection, ProviderRegistry $crmProviderRegistry, array $visitors = [])
{
$this->connection = $connection;
$this->providerRegistry = $crmProviderRegistry;
foreach ($visitors as $visitor) {
$this->visitors[$visitor->getIdentifier()] = $visitor;
}
}
public function getDeals(CriteriaInterface $criteria): array
{
$context = $criteria->getContext();
$team = $context->getTeam();
$crmService = $this->getCrmService($team);
$qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);
$qb = $this->getSearchSelectAndWhereClauses($qb);
$this->visit($qb, $criteria);
return $this->execute($team, $crmService, $qb);
}
public function getDeal(Team $team, int $id): array
{
$crmService = $this->getCrmService($team);
$qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);
$qb = $this->getSearchSelectAndWhereClauses($qb);
$qb->andWhere('opp.id = :id')->setParameter('id', $id);
return $this->execute($team, $crmService, $qb);
}
public function getCrmFieldData(array $crmFields, int $crmId, array $opportunityIds = [])
{
$qb = new QueryBuilder($this->connection);
$qb
->select('f.id', 'f.crm_provider_id AS field_name', 'f.label', 'fd.object_id AS dealId', 'fd.value')
->from('crm_fields', 'f')
->join('f', 'crm_field_data', 'fd', 'fd.crm_field_id = f.id')
->where('f.crm_configuration_id = :crm')
->andWhere('f.object_type = :type')
->andWhere('fd.object_id IN (' . implode(',', $opportunityIds) . ')')
->orderBy('fd.object_id', 'ASC')
->addOrderBy('fd.updated_at', 'ASC')
->setParameter('type', Field::OBJECT_OPPORTUNITY)
->setParameter('crm', $crmId)
;
if (! empty($crmFields)) {
$fields = array_map(fn ($value): string => '"' . $value . '"', $crmFields);
$qb->andWhere('f.crm_provider_id IN (' . implode(',', $fields) . ')');
}
return $qb->executeQuery()->fetchAllAssociative();
}
public function getTotalsInDefaultCurrency(CriteriaInterface $criteria): array
{
$qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);
$qb
->select('SUM(opp.value) as total')
->addSelect('count(*) as `count`')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'))
;
$this->visit($qb, $criteria);
return $qb->executeQuery()->fetchAssociative();
}
public function getTotals(CriteriaInterface $criteria, string $defaultCurrency): array
{
$qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);
$qb
->select('COALESCE(opp.currency_code, "' . $defaultCurrency . '") AS currency')
->addSelect('SUM(opp.value) as total')
->addSelect('count(*) as `count`')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'))
->groupBy('currency')
;
$this->visit($qb, $criteria);
return $qb->executeQuery()->fetchAllAssociative();
}
public function getDealActivities(CriteriaInterface $criteria): array
{
$qb = Activity::with(['participants', 'user'])
->where('opportunity_id', $criteria->getOpportunityId())
->whereDate('actual_start_time', '>=', $criteria->getPeriod()->getStartDate())
->whereDate('actual_start_time', '<=', $criteria->getPeriod()->getEndDate())
->orderBy($criteria->getSortBy(), $criteria->getSortDirection())
;
// Should we filter activities by criteria? It's intended to filter deals.
return $qb->get()->all();
}
public function getStages(CriteriaInterface $criteria): array
{
$qb = new QueryBuilder($this->connection);
$qb
->select('id', 'label', 'sequence')
->from('stages', 's')
->where('crm_configuration_id = :crm_configuration_id')
->andWhere('type = :type')
->orderBy('sequence', 'ASC')
->setParameter('crm_configuration_id', $criteria->getContext()->getTeam()->getCrmConfiguration()->getId())
->setParameter('type', Stage::TYPE_OPPORTUNITY);
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$result[$row['id']] = [
'label' => $row['label'],
'sequence' => $row['sequence'],
];
}
return $result;
}
public function getConfigurationStages(Configuration $configuration): Collection
{
return $configuration
->stages()
->where('type', Stage::TYPE_OPPORTUNITY)
->get();
}
public function getPipelineData(Configuration $crm): array
{
$qb = new QueryBuilder($this->connection);
$provider = $crm->provider;
$qb
->select('s.label', 's.crm_provider_id', 's.sequence', 'bps.business_process_id AS pipeline_id')
->from('stages', 's')
->join('s', 'business_process_stages', 'bps', 's.id=bps.stage_id')
->where('s.crm_configuration_id = :crm_configuration_id')
->andWhere('s.type = :type')
->orderBy('bps.business_process_id', 'ASC')
->addOrderBy('s.sequence', 'ASC')
->setParameter('crm_configuration_id', $crm->id)
->setParameter('type', Stage::TYPE_OPPORTUNITY)
;
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$value = $provider === Configuration::PROVIDER_SALESFORCE ? $row['label'] : $row['crm_provider_id'];
$result[$row['pipeline_id']][] = [
'value' => $value,
'label' => $row['label'],
'sequence' => $row['sequence'],
];
}
return $result;
}
private function createQueryBuilder(string $realm): QueryBuilder
{
return (new QueryBuilder($this->connection))
->setRealm($realm)
->from('opportunities', 'opp')
->leftJoin('opp', 'record_types', 'rt', 'opp.record_type_id = rt.id')
->leftJoin('opp', 'users', 'usr', 'opp.user_id = usr.id')
->leftJoin('opp', 'accounts', 'acc', 'opp.account_id = acc.id')
;
}
/**
* Applies all applicable visitors and returns the IDs of the executed ones
*
* @return string[]
*/
private function visit(QueryBuilder $queryBuilder, CriteriaInterface $criteria): array
{
$queryVisitors = [];
foreach ($this->visitors as $visitor) {
if ($visitor->isSatisfiedBy($criteria, $queryBuilder->getRealm())) {
$visitor->visit($queryBuilder, $criteria);
$queryVisitors[] = $visitor->getIdentifier();
}
}
return $queryVisitors;
}
private function hydrateStages(array $deals): array
{
foreach ($this->fetchStages(array_keys($deals)) as $stage) {
$oppId = (int) $stage['opportunity_id'];
if (! isset($deals[$oppId])) {
continue; // or throw??!
}
$deals[$oppId]['stages'][] = [
'id' => $stage['stage_id'],
'name' => $stage['label'],
'enteredAt' => $stage['created_at'],
];
}
return $deals;
}
/**
* @param int[] $dealIds
*/
private function fetchStages(array $dealIds): array
{
if (empty($dealIds)) {
return [];
}
$qb = new QueryBuilder($this->connection);
$qb
->select('os.opportunity_id', 's.id AS stage_id', 's.label', 's.created_at')
->from('opportunity_stages', 'os')
->leftJoin('os', 'stages', 's', 'os.stage_id=s.id')
->where($qb->expr()->in('os.opportunity_id', $dealIds))
->orderBy('os.opportunity_id', 'ASC')
->addOrderBy('s.created_at', 'ASC')
;
return $qb->executeQuery()->fetchAllAssociative();
}
private function execute(Team $team, ServiceInterface $crmService, QueryBuilder $qb): array
{
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$data = [
'uuid' => RequiresUUID::toNormal($row['uuid']),
'name' => $row['name'],
'url' => $crmService->generateProviderUrl($row['opp_provider_id'], 'opportunity'),
'account' => [
'name' => $row['acc_name'],
'url' => $crmService->generateProviderUrl(
providerId: $row['acc_provider_id'],
objectType: $row['acc_is_internal'] ? 'internal-account' : 'account'
),
],
'owner' => null,
'rawValue' => [
'amount' => (float) $row['value'],
'currency' => $row['currency_code'],
],
'value' => formatOpportunityValue((float) $row['value'], $row['currency_code']),
'openDate' => $row['remotely_created_at'] ?? null,
'closeDate' => $row['close_date'] ?? null,
'stages' => [],
'currentPipelineId' => $row['pipeline_id'],
'currentStage' => [
'id' => $row['stage_id'],
'enteredAt' => $row['stage_updated_at'],
],
'currentStageUpdatedAt' => $row['stage_updated_at'],
'isClosed' => (bool) $row['is_closed'],
'isWon' => (bool) $row['is_won'],
];
if (isset($row['owner_uuid'])) {
$data['owner'] = [
'uuid' => RequiresUUID::toNormal($row['owner_uuid']),
'name' => $row['owner_name'],
'photoUrl' => $row['owner_photo'] === null
? null
: client_cdn($row['owner_photo'], $team),
'id' => $row['owner_id'],
'job' => $row['owner_job'],
];
}
$result[(int) $row['opp_id']] = $data;
}
return $this->hydrateStages($result);
}
private function getSearchSelectAndWhereClauses(QueryBuilder $queryBuilder): QueryBuilder
{
$qb = clone $queryBuilder;
$qb->leftJoin('usr', 'job_titles', 'jt', 'usr.job_title_id = jt.id');
$qb
->select(...[
'opp.id as opp_id',
'opp.uuid',
'opp.name',
'opp.value',
'opp.currency_code',
'opp.close_date',
'opp.remotely_created_at',
'opp.is_closed',
'opp.is_won',
])
->addSelect(...[
'usr.uuid as owner_uuid',
'usr.name AS owner_name',
'usr.photo_path as owner_photo',
'usr.id AS owner_id',
'jt.name as owner_job',
])
->addSelect('opp.stage_id', 'opp.stage_updated_at')
->addSelect(...[
'acc.name AS acc_name',
'acc.is_internal as acc_is_internal',
'opp.stage_updated_at',
'acc.crm_provider_id AS acc_provider_id',
'opp.crm_provider_id AS opp_provider_id',
])
->addSelect('rt.business_process_id AS pipeline_id')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not display deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'));
return $qb;
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws SocialAccountTokenInvalidException
*/
private function getCrmService(Team $team): ServiceInterface
{
$crmService = $this->providerRegistry->get($team->crm->provider);
$crmService->setConfiguration($team->crm);
if ($crmService instanceof UrlGeneratorInterface) {
$crmService->setCrmUrlGenerator($team->crm);
}
return $crmService;
}
/**
*
* @return Generator<DealData>
*/
public function getForecastData(DealsFilter $filter): Generator
{
$opportunities = DB::query()
->select([
'o.value',
'o.close_date',
'o.currency_code',
'o.is_won',
'o.is_closed',
'o.probability',
'o.forecast_category',
])
->from('opportunities', 'o')
->join('users', 'users.id', '=', 'o.user_id')
->join('groups', 'groups.id', '=', 'users.group_id')
->where('users.team_id', $filter->getTeam()->getId())
->where('o.close_date', '>=', $filter->getStartDate())
->where('o.close_date', '<=', $filter->getEndDate())
->where('o.currency_code', $filter->getCurrency())
->where('o.deleted_at', '=', null)
;
$userUuidList = $filter->getUserUuidList();
if (! empty($userUuidList)) {
$userUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $userUuidList);
$opportunities->whereIn('users.uuid', $userUuidList);
}
$groupUuidList = $filter->getGroupUuidList();
if (! empty($groupUuidList)) {
$groupUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $groupUuidList);
$opportunities->whereIn('groups.uuid', $groupUuidList);
}
foreach ($opportunities->cursor() as $row) {
yield new DealData(
(float) $row->value,
$row->close_date,
! empty($row->is_won),
! empty($row->is_closed),
$row->probability ?: 0,
$row->forecast_category ?: '',
);
}
}
public function getUserOpportunitySubscriptions(User $user, array $opportunityIds): Collection
{
return $user->subscriptionSets()
->where(static function (Eloquent\Builder $query): void {
$query
->whereNull('expired_at')
->orWhere('expired_at', '>=', now());
})
->join('activity_subscriptions', function (Builder $join) use ($opportunityIds) {
$join
->on('subscription_set_id', '=', 'activity_subscription_sets.id');
$join
->where('followable_type', Models\Activity\Subscription::FOLLOWABLE_TYPE_OPPORTUNITY)
->whereIn('followable_id', $opportunityIds);
})
->pluck('followable_id');
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Git Branch: JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"RequestGenerateAskJiminnyReportJobTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Http\\Transformers;\n\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\Sidekick\\SidekickService;\nuse Jiminny\\Exceptions\\ActivityProviderException;\nuse Jiminny\\Http\\Controllers\\Settings\\Users\\Utils\\UserSetting;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\JobTitle;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Notification\\Messengers\\MsTeams;\nuse Jiminny\\Services\\UserService;\nuse League\\Fractal\\Resource;\nuse League\\Fractal\\Resource\\Item;\nuse League\\Fractal\\TransformerAbstract;\n\nclass UserTransformer extends TransformerAbstract\n{\n protected array $availableIncludes = [\n 'team',\n 'group',\n 'job',\n 'roles',\n 'permissions',\n ];\n\n private Container $container;\n\n private bool $withSelfVisibility = false;\n\n public function __construct(?Container $container = null)\n {\n $this->container = $container ?? app();\n }\n\n public function withSelfVisibility(): self\n {\n $this->withSelfVisibility = true;\n\n return $this;\n }\n\n /**\n * @throws ActivityProviderException\n *\n * @return array<string, mixed>\n */\n public function transform(User $user): array\n {\n $attributes = [\n 'id' => $user->getUuid(),\n 'name' => $user->getName(),\n 'firstName' => $user->getFirstName(),\n 'photoUrl' => $user->getPhotoUrl(),\n 'conferenceRecordPreference' => $user->checkConferenceRecordPreference(),\n 'conferenceRecordInternalPreference' => $user->checkConferenceRecordInternalPreference(),\n // DO NOT USE User::isCrmRequired as it is not hydrated when fetched from ES!\n 'crmRequired' => $user->crm_required,\n 'slackFollowUp' => $user->slack_follow_up,\n ];\n\n // DO NOT USE User::getId as it is not hydrated when fetched from ES!\n if ($this->withSelfVisibility || (auth()->check() && auth()->user()->id === $user->id)) {\n $softphoneHasVoiceCapability = $user->hasSoftphoneNumberCapabilities()\n && $user->getSoftphoneNumberCapabilities()->hasVoiceCapability()\n ;\n\n $conferenceSidekickOpen = $user->getConferenceSidekickOpen();\n $softphoneSidekickOpen = $user->getSoftphoneSidekickOpen();\n $conferenceSidekickPopupOverridden = false;\n $softphoneSidekickPopupOverridden = false;\n $hasSidekickEnabled = true;\n\n if ($user->getTeam()->hasFeature(FeatureEnum::SIDEKICK_SETTINGS)) {\n $sidekickService = $this->getSidekickService();\n\n $sidekickData = $sidekickService->getSidekickSettingsForUser($user);\n\n $conferenceSidekickOpen = $sidekickData['conferenceSettings'];\n $softphoneSidekickOpen = $sidekickData['softphoneSettings'];\n $conferenceSidekickPopupOverridden = $sidekickData['conferenceSidekickPopupOverridden'];\n $softphoneSidekickPopupOverridden = $sidekickData['softphoneSidekickPopupOverridden'];\n $hasSidekickEnabled = $sidekickData['sidekickEnabled'];\n }\n\n $userService = $this->getUserService();\n $dealInsightsPeriod = $userService->getDealInsightTimelinePeriod($user);\n $dataFormatCountryCode = $userService->getDateTimeCountryCode($user);\n\n // Attributes for the user only.\n $attributes += [\n 'conferenceJoinReminder' => $user->conference_join_reminder,\n 'softphoneInboundRecordPreference' => $user->checkSoftphoneInboundRecordPreference(),\n 'softphoneOutboundRecordPreference' => $user->checkSoftphoneOutboundRecordPreference(),\n 'softphoneInboundDestination' => $user->softphone_inbound_destination,\n 'softphoneHasVoiceCapability' => $softphoneHasVoiceCapability,\n 'softphoneNumber' => $user->getSoftPhoneNumber(),\n 'formattedSoftphoneNumber' => $user->getFormattedSoftphoneNumberAttribute(),\n 'email' => $user->getEmailAddress(),\n 'secondaryEmail' => $user->getSecondaryEmailAddress(),\n 'phone' => $user->phone,\n 'secondaryPhone' => $user->secondary_phone,\n 'callerId' => $user->getCallerId(),\n 'countryCode' => $user->getCountryCode(),\n 'timezone' => $user->getTimezone()->getName(),\n 'language' => $user->getLanguage(),\n 'locales' => $this->container->get(UserRepository::class)->getUserLocales($user),\n 'status' => $user->getStatus(),\n 'hash' => $user->generateHash(),\n 'registrationDate' => $user->created_at ? $user->created_at->toIso8601String() : null,\n 'notifyLiveCoaching' => $user->notify_live_coaching,\n 'activityLogReminder' => $user->activity_log_reminder,\n 'conferenceSidekickOpen' => $conferenceSidekickOpen,\n 'softphoneSidekickOpen' => $softphoneSidekickOpen,\n 'conferenceSidekickPopupOverridden' => $conferenceSidekickPopupOverridden,\n 'softphoneSidekickPopupOverridden' => $softphoneSidekickPopupOverridden,\n 'hasSidekickEnabled' => $hasSidekickEnabled,\n 'activityActionItems' => $user->activity_action_items,\n 'syncEmail' => $user->isSyncEmailEnabled(),\n 'syncConference' => $user->sync_conference,\n 'syncDialer' => $user->shouldSyncDialer(),\n 'needsToConfigurePhoneNumber' => $this->container\n ->get('onboarding_phone_decider')\n ->isOnboardable($user),\n 'shouldShowPhoneNumberField' => $this->container\n ->get('onboarding_phone_decider')\n ->shouldShowPhoneNumberField($user),\n UserSetting::DEAL_INSIGHTS_TIMELINE_PERIOD => $dealInsightsPeriod,\n 'countryByTimezone' => $dataFormatCountryCode,\n 'conferenceSlug' => $user->getConferenceSlug(),\n 'conferenceRecordExternalOrganizerPreference' =>\n $userService->isConferenceRecordExternalOrganizerPreferenceEnabled($user),\n 'hasGeneratedAiReports' => $this->getAutomatedReportsRepository()->countUserReports($user) > 0,\n 'sendEmailWhenExportLinkIsOpened' => $userService->canSendEmailWhenExportLinkIsOpened($user),\n ];\n\n if ($user->softphone_debug) {\n $attributes += [\n 'debugSoftphone' => $user->softphone_debug, // Needed?\n ];\n }\n }\n\n if ($user->getTeam()->getNotificationProvider() === Team::NOTIFICATION_PROVIDER_MSTEAMS) {\n $socialAccountMS = $user->getSocialAccount(Team::CALENDAR_PROVIDER_OFFICE);\n $state = $socialAccountMS !== null\n ? str_contains($socialAccountMS->auth_scope, MsTeams::SCOPE_CHAT_CREATE)\n : null;\n\n $attributes['integrations']['office'] = [\n 'displayName' => 'Microsoft Teams',\n 'apiName' => 'microsoft-teams',\n 'types' => ['notification'],\n 'state' => $state ? Provider::STATE_INSTALLED : Provider::STATE_NOT_INSTALLED,\n 'logo' => cdn('img/ms-teams-logo.svg'),\n 'installationStrategy' => 'oauth',\n ];\n }\n\n return $attributes;\n }\n\n public function includeTeam(User $user): Item\n {\n $team = $user->getTeam();\n\n return $this->item($team, $this->getTeamTransformer());\n }\n\n public function includeGroup(User $user): ?Item\n {\n $group = $user->getGroup();\n if ($group === null) {\n return null;\n }\n\n return $this->item($group, $this->getGroupTransformer());\n }\n\n public function includeJob(User $user): ?Item\n {\n $job = $user->getJobTitle();\n\n if (! $job instanceof JobTitle) {\n return null;\n }\n\n return $this->item($job, $this->getJobTitleTransformer());\n }\n\n public function includeRoles(User $user): Resource\\Collection\n {\n /** @var Collection<int, string> $roles */\n $roles = $user->roles()\n ->where('is_visible', true)\n ->pluck('name')\n ->toArray();\n\n return $this->collection($roles, $this->getRoleTransformer());\n }\n\n public function includePermissions(User $user): Resource\\Collection\n {\n $permissions = $user->allPermissions();\n\n return $this->collection($permissions, $this->getPermissionTransformer());\n }\n\n public function includeIntegrations(User $user): Item\n {\n return $this->item($user, $this->getIntegrationsTransformer());\n }\n\n private function getTeamTransformer(): TransformerAbstract\n {\n return $this->container->get(TeamTransformer::class);\n }\n\n private function getGroupTransformer(): GroupTransformer\n {\n return $this->container->get(GroupTransformer::class);\n }\n\n private function getIntegrationsTransformer(): IntegrationTransformer\n {\n return $this->container->get(IntegrationTransformer::class);\n }\n\n private function getPermissionTransformer(): PermissionTransformer\n {\n return $this->container->get(PermissionTransformer::class);\n }\n\n private function getRoleTransformer(): RoleTransformer\n {\n return $this->container->get(RoleTransformer::class);\n }\n\n private function getJobTitleTransformer(): JobTitleTransformer\n {\n return $this->container->get(JobTitleTransformer::class);\n }\n\n private function getSidekickService(): SidekickService\n {\n /** @var SidekickService */\n return $this->container->get(SidekickService::class);\n }\n\n private function getUserService(): UserService\n {\n /** @var UserService */\n return $this->container->get(UserService::class);\n }\n\n private function getAutomatedReportsRepository(): AutomatedReportsRepository\n {\n /** @var AutomatedReportsRepository */\n return $this->container->get(AutomatedReportsRepository::class);\n }\n}","depth":4,"value":"<?php\n\nnamespace Jiminny\\Http\\Transformers;\n\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\Sidekick\\SidekickService;\nuse Jiminny\\Exceptions\\ActivityProviderException;\nuse Jiminny\\Http\\Controllers\\Settings\\Users\\Utils\\UserSetting;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\JobTitle;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Notification\\Messengers\\MsTeams;\nuse Jiminny\\Services\\UserService;\nuse League\\Fractal\\Resource;\nuse League\\Fractal\\Resource\\Item;\nuse League\\Fractal\\TransformerAbstract;\n\nclass UserTransformer extends TransformerAbstract\n{\n protected array $availableIncludes = [\n 'team',\n 'group',\n 'job',\n 'roles',\n 'permissions',\n ];\n\n private Container $container;\n\n private bool $withSelfVisibility = false;\n\n public function __construct(?Container $container = null)\n {\n $this->container = $container ?? app();\n }\n\n public function withSelfVisibility(): self\n {\n $this->withSelfVisibility = true;\n\n return $this;\n }\n\n /**\n * @throws ActivityProviderException\n *\n * @return array<string, mixed>\n */\n public function transform(User $user): array\n {\n $attributes = [\n 'id' => $user->getUuid(),\n 'name' => $user->getName(),\n 'firstName' => $user->getFirstName(),\n 'photoUrl' => $user->getPhotoUrl(),\n 'conferenceRecordPreference' => $user->checkConferenceRecordPreference(),\n 'conferenceRecordInternalPreference' => $user->checkConferenceRecordInternalPreference(),\n // DO NOT USE User::isCrmRequired as it is not hydrated when fetched from ES!\n 'crmRequired' => $user->crm_required,\n 'slackFollowUp' => $user->slack_follow_up,\n ];\n\n // DO NOT USE User::getId as it is not hydrated when fetched from ES!\n if ($this->withSelfVisibility || (auth()->check() && auth()->user()->id === $user->id)) {\n $softphoneHasVoiceCapability = $user->hasSoftphoneNumberCapabilities()\n && $user->getSoftphoneNumberCapabilities()->hasVoiceCapability()\n ;\n\n $conferenceSidekickOpen = $user->getConferenceSidekickOpen();\n $softphoneSidekickOpen = $user->getSoftphoneSidekickOpen();\n $conferenceSidekickPopupOverridden = false;\n $softphoneSidekickPopupOverridden = false;\n $hasSidekickEnabled = true;\n\n if ($user->getTeam()->hasFeature(FeatureEnum::SIDEKICK_SETTINGS)) {\n $sidekickService = $this->getSidekickService();\n\n $sidekickData = $sidekickService->getSidekickSettingsForUser($user);\n\n $conferenceSidekickOpen = $sidekickData['conferenceSettings'];\n $softphoneSidekickOpen = $sidekickData['softphoneSettings'];\n $conferenceSidekickPopupOverridden = $sidekickData['conferenceSidekickPopupOverridden'];\n $softphoneSidekickPopupOverridden = $sidekickData['softphoneSidekickPopupOverridden'];\n $hasSidekickEnabled = $sidekickData['sidekickEnabled'];\n }\n\n $userService = $this->getUserService();\n $dealInsightsPeriod = $userService->getDealInsightTimelinePeriod($user);\n $dataFormatCountryCode = $userService->getDateTimeCountryCode($user);\n\n // Attributes for the user only.\n $attributes += [\n 'conferenceJoinReminder' => $user->conference_join_reminder,\n 'softphoneInboundRecordPreference' => $user->checkSoftphoneInboundRecordPreference(),\n 'softphoneOutboundRecordPreference' => $user->checkSoftphoneOutboundRecordPreference(),\n 'softphoneInboundDestination' => $user->softphone_inbound_destination,\n 'softphoneHasVoiceCapability' => $softphoneHasVoiceCapability,\n 'softphoneNumber' => $user->getSoftPhoneNumber(),\n 'formattedSoftphoneNumber' => $user->getFormattedSoftphoneNumberAttribute(),\n 'email' => $user->getEmailAddress(),\n 'secondaryEmail' => $user->getSecondaryEmailAddress(),\n 'phone' => $user->phone,\n 'secondaryPhone' => $user->secondary_phone,\n 'callerId' => $user->getCallerId(),\n 'countryCode' => $user->getCountryCode(),\n 'timezone' => $user->getTimezone()->getName(),\n 'language' => $user->getLanguage(),\n 'locales' => $this->container->get(UserRepository::class)->getUserLocales($user),\n 'status' => $user->getStatus(),\n 'hash' => $user->generateHash(),\n 'registrationDate' => $user->created_at ? $user->created_at->toIso8601String() : null,\n 'notifyLiveCoaching' => $user->notify_live_coaching,\n 'activityLogReminder' => $user->activity_log_reminder,\n 'conferenceSidekickOpen' => $conferenceSidekickOpen,\n 'softphoneSidekickOpen' => $softphoneSidekickOpen,\n 'conferenceSidekickPopupOverridden' => $conferenceSidekickPopupOverridden,\n 'softphoneSidekickPopupOverridden' => $softphoneSidekickPopupOverridden,\n 'hasSidekickEnabled' => $hasSidekickEnabled,\n 'activityActionItems' => $user->activity_action_items,\n 'syncEmail' => $user->isSyncEmailEnabled(),\n 'syncConference' => $user->sync_conference,\n 'syncDialer' => $user->shouldSyncDialer(),\n 'needsToConfigurePhoneNumber' => $this->container\n ->get('onboarding_phone_decider')\n ->isOnboardable($user),\n 'shouldShowPhoneNumberField' => $this->container\n ->get('onboarding_phone_decider')\n ->shouldShowPhoneNumberField($user),\n UserSetting::DEAL_INSIGHTS_TIMELINE_PERIOD => $dealInsightsPeriod,\n 'countryByTimezone' => $dataFormatCountryCode,\n 'conferenceSlug' => $user->getConferenceSlug(),\n 'conferenceRecordExternalOrganizerPreference' =>\n $userService->isConferenceRecordExternalOrganizerPreferenceEnabled($user),\n 'hasGeneratedAiReports' => $this->getAutomatedReportsRepository()->countUserReports($user) > 0,\n 'sendEmailWhenExportLinkIsOpened' => $userService->canSendEmailWhenExportLinkIsOpened($user),\n ];\n\n if ($user->softphone_debug) {\n $attributes += [\n 'debugSoftphone' => $user->softphone_debug, // Needed?\n ];\n }\n }\n\n if ($user->getTeam()->getNotificationProvider() === Team::NOTIFICATION_PROVIDER_MSTEAMS) {\n $socialAccountMS = $user->getSocialAccount(Team::CALENDAR_PROVIDER_OFFICE);\n $state = $socialAccountMS !== null\n ? str_contains($socialAccountMS->auth_scope, MsTeams::SCOPE_CHAT_CREATE)\n : null;\n\n $attributes['integrations']['office'] = [\n 'displayName' => 'Microsoft Teams',\n 'apiName' => 'microsoft-teams',\n 'types' => ['notification'],\n 'state' => $state ? Provider::STATE_INSTALLED : Provider::STATE_NOT_INSTALLED,\n 'logo' => cdn('img/ms-teams-logo.svg'),\n 'installationStrategy' => 'oauth',\n ];\n }\n\n return $attributes;\n }\n\n public function includeTeam(User $user): Item\n {\n $team = $user->getTeam();\n\n return $this->item($team, $this->getTeamTransformer());\n }\n\n public function includeGroup(User $user): ?Item\n {\n $group = $user->getGroup();\n if ($group === null) {\n return null;\n }\n\n return $this->item($group, $this->getGroupTransformer());\n }\n\n public function includeJob(User $user): ?Item\n {\n $job = $user->getJobTitle();\n\n if (! $job instanceof JobTitle) {\n return null;\n }\n\n return $this->item($job, $this->getJobTitleTransformer());\n }\n\n public function includeRoles(User $user): Resource\\Collection\n {\n /** @var Collection<int, string> $roles */\n $roles = $user->roles()\n ->where('is_visible', true)\n ->pluck('name')\n ->toArray();\n\n return $this->collection($roles, $this->getRoleTransformer());\n }\n\n public function includePermissions(User $user): Resource\\Collection\n {\n $permissions = $user->allPermissions();\n\n return $this->collection($permissions, $this->getPermissionTransformer());\n }\n\n public function includeIntegrations(User $user): Item\n {\n return $this->item($user, $this->getIntegrationsTransformer());\n }\n\n private function getTeamTransformer(): TransformerAbstract\n {\n return $this->container->get(TeamTransformer::class);\n }\n\n private function getGroupTransformer(): GroupTransformer\n {\n return $this->container->get(GroupTransformer::class);\n }\n\n private function getIntegrationsTransformer(): IntegrationTransformer\n {\n return $this->container->get(IntegrationTransformer::class);\n }\n\n private function getPermissionTransformer(): PermissionTransformer\n {\n return $this->container->get(PermissionTransformer::class);\n }\n\n private function getRoleTransformer(): RoleTransformer\n {\n return $this->container->get(RoleTransformer::class);\n }\n\n private function getJobTitleTransformer(): JobTitleTransformer\n {\n return $this->container->get(JobTitleTransformer::class);\n }\n\n private function getSidekickService(): SidekickService\n {\n /** @var SidekickService */\n return $this->container->get(SidekickService::class);\n }\n\n private function getUserService(): UserService\n {\n /** @var UserService */\n return $this->container->get(UserService::class);\n }\n\n private function getAutomatedReportsRepository(): AutomatedReportsRepository\n {\n /** @var AutomatedReportsRepository */\n return $this->container->get(AutomatedReportsRepository::class);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"36","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\DealInsights;\n\nuse Doctrine\\DBAL\\Connection;\nuse Generator;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Facades\\DB;\nuse Jiminny\\Component\\DealInsights\\Forecast\\DealData;\nuse Jiminny\\Component\\DealInsights\\Forecast\\DealsFilter;\nuse Jiminny\\Component\\DealInsights\\QueryBuilder\\QueryBuilder;\nuse Jiminny\\Component\\DealInsights\\QueryBuilder\\Visitor\\QueryBuilderVisitorInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Models;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\Utils\\UrlGeneratorInterface;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Database\\Eloquent;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\n\nclass DealsRepository implements DealsRepositoryInterface\n{\n private Connection $connection;\n\n private ProviderRegistry $providerRegistry;\n\n /**\n * @var QueryBuilderVisitorInterface[]\n */\n private array $visitors = [];\n\n /**\n * @param QueryBuilderVisitorInterface[] $visitors\n */\n public function __construct(Connection $connection, ProviderRegistry $crmProviderRegistry, array $visitors = [])\n {\n $this->connection = $connection;\n $this->providerRegistry = $crmProviderRegistry;\n\n foreach ($visitors as $visitor) {\n $this->visitors[$visitor->getIdentifier()] = $visitor;\n }\n }\n\n public function getDeals(CriteriaInterface $criteria): array\n {\n $context = $criteria->getContext();\n $team = $context->getTeam();\n $crmService = $this->getCrmService($team);\n\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);\n $qb = $this->getSearchSelectAndWhereClauses($qb);\n\n $this->visit($qb, $criteria);\n\n return $this->execute($team, $crmService, $qb);\n }\n\n public function getDeal(Team $team, int $id): array\n {\n $crmService = $this->getCrmService($team);\n\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);\n $qb = $this->getSearchSelectAndWhereClauses($qb);\n $qb->andWhere('opp.id = :id')->setParameter('id', $id);\n\n return $this->execute($team, $crmService, $qb);\n }\n\n public function getCrmFieldData(array $crmFields, int $crmId, array $opportunityIds = [])\n {\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('f.id', 'f.crm_provider_id AS field_name', 'f.label', 'fd.object_id AS dealId', 'fd.value')\n ->from('crm_fields', 'f')\n ->join('f', 'crm_field_data', 'fd', 'fd.crm_field_id = f.id')\n ->where('f.crm_configuration_id = :crm')\n ->andWhere('f.object_type = :type')\n ->andWhere('fd.object_id IN (' . implode(',', $opportunityIds) . ')')\n ->orderBy('fd.object_id', 'ASC')\n ->addOrderBy('fd.updated_at', 'ASC')\n\n ->setParameter('type', Field::OBJECT_OPPORTUNITY)\n ->setParameter('crm', $crmId)\n ;\n\n if (! empty($crmFields)) {\n $fields = array_map(fn ($value): string => '\"' . $value . '\"', $crmFields);\n $qb->andWhere('f.crm_provider_id IN (' . implode(',', $fields) . ')');\n }\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n public function getTotalsInDefaultCurrency(CriteriaInterface $criteria): array\n {\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);\n\n $qb\n ->select('SUM(opp.value) as total')\n ->addSelect('count(*) as `count`')\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'))\n ;\n\n $this->visit($qb, $criteria);\n\n return $qb->executeQuery()->fetchAssociative();\n }\n\n public function getTotals(CriteriaInterface $criteria, string $defaultCurrency): array\n {\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);\n\n $qb\n ->select('COALESCE(opp.currency_code, \"' . $defaultCurrency . '\") AS currency')\n ->addSelect('SUM(opp.value) as total')\n ->addSelect('count(*) as `count`')\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'))\n ->groupBy('currency')\n ;\n\n $this->visit($qb, $criteria);\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n public function getDealActivities(CriteriaInterface $criteria): array\n {\n $qb = Activity::with(['participants', 'user'])\n ->where('opportunity_id', $criteria->getOpportunityId())\n ->whereDate('actual_start_time', '>=', $criteria->getPeriod()->getStartDate())\n ->whereDate('actual_start_time', '<=', $criteria->getPeriod()->getEndDate())\n ->orderBy($criteria->getSortBy(), $criteria->getSortDirection())\n ;\n\n // Should we filter activities by criteria? It's intended to filter deals.\n\n return $qb->get()->all();\n }\n\n public function getStages(CriteriaInterface $criteria): array\n {\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('id', 'label', 'sequence')\n ->from('stages', 's')\n ->where('crm_configuration_id = :crm_configuration_id')\n ->andWhere('type = :type')\n ->orderBy('sequence', 'ASC')\n\n ->setParameter('crm_configuration_id', $criteria->getContext()->getTeam()->getCrmConfiguration()->getId())\n ->setParameter('type', Stage::TYPE_OPPORTUNITY);\n\n $result = [];\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $result[$row['id']] = [\n 'label' => $row['label'],\n 'sequence' => $row['sequence'],\n ];\n }\n\n return $result;\n }\n\n public function getConfigurationStages(Configuration $configuration): Collection\n {\n return $configuration\n ->stages()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get();\n }\n\n public function getPipelineData(Configuration $crm): array\n {\n $qb = new QueryBuilder($this->connection);\n $provider = $crm->provider;\n\n $qb\n ->select('s.label', 's.crm_provider_id', 's.sequence', 'bps.business_process_id AS pipeline_id')\n ->from('stages', 's')\n ->join('s', 'business_process_stages', 'bps', 's.id=bps.stage_id')\n ->where('s.crm_configuration_id = :crm_configuration_id')\n ->andWhere('s.type = :type')\n ->orderBy('bps.business_process_id', 'ASC')\n ->addOrderBy('s.sequence', 'ASC')\n\n ->setParameter('crm_configuration_id', $crm->id)\n ->setParameter('type', Stage::TYPE_OPPORTUNITY)\n ;\n\n $result = [];\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $value = $provider === Configuration::PROVIDER_SALESFORCE ? $row['label'] : $row['crm_provider_id'];\n $result[$row['pipeline_id']][] = [\n 'value' => $value,\n 'label' => $row['label'],\n 'sequence' => $row['sequence'],\n ];\n }\n\n return $result;\n }\n\n private function createQueryBuilder(string $realm): QueryBuilder\n {\n return (new QueryBuilder($this->connection))\n ->setRealm($realm)\n ->from('opportunities', 'opp')\n ->leftJoin('opp', 'record_types', 'rt', 'opp.record_type_id = rt.id')\n ->leftJoin('opp', 'users', 'usr', 'opp.user_id = usr.id')\n ->leftJoin('opp', 'accounts', 'acc', 'opp.account_id = acc.id')\n ;\n }\n\n /**\n * Applies all applicable visitors and returns the IDs of the executed ones\n *\n * @return string[]\n */\n private function visit(QueryBuilder $queryBuilder, CriteriaInterface $criteria): array\n {\n $queryVisitors = [];\n\n foreach ($this->visitors as $visitor) {\n if ($visitor->isSatisfiedBy($criteria, $queryBuilder->getRealm())) {\n $visitor->visit($queryBuilder, $criteria);\n\n $queryVisitors[] = $visitor->getIdentifier();\n }\n }\n\n return $queryVisitors;\n }\n\n private function hydrateStages(array $deals): array\n {\n foreach ($this->fetchStages(array_keys($deals)) as $stage) {\n $oppId = (int) $stage['opportunity_id'];\n\n if (! isset($deals[$oppId])) {\n continue; // or throw??!\n }\n\n $deals[$oppId]['stages'][] = [\n 'id' => $stage['stage_id'],\n 'name' => $stage['label'],\n 'enteredAt' => $stage['created_at'],\n ];\n }\n\n return $deals;\n }\n\n /**\n * @param int[] $dealIds\n */\n private function fetchStages(array $dealIds): array\n {\n if (empty($dealIds)) {\n return [];\n }\n\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('os.opportunity_id', 's.id AS stage_id', 's.label', 's.created_at')\n ->from('opportunity_stages', 'os')\n ->leftJoin('os', 'stages', 's', 'os.stage_id=s.id')\n ->where($qb->expr()->in('os.opportunity_id', $dealIds))\n ->orderBy('os.opportunity_id', 'ASC')\n ->addOrderBy('s.created_at', 'ASC')\n ;\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n private function execute(Team $team, ServiceInterface $crmService, QueryBuilder $qb): array\n {\n $result = [];\n\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $data = [\n 'uuid' => RequiresUUID::toNormal($row['uuid']),\n 'name' => $row['name'],\n 'url' => $crmService->generateProviderUrl($row['opp_provider_id'], 'opportunity'),\n 'account' => [\n 'name' => $row['acc_name'],\n 'url' => $crmService->generateProviderUrl(\n providerId: $row['acc_provider_id'],\n objectType: $row['acc_is_internal'] ? 'internal-account' : 'account'\n ),\n ],\n 'owner' => null,\n 'rawValue' => [\n 'amount' => (float) $row['value'],\n 'currency' => $row['currency_code'],\n ],\n 'value' => formatOpportunityValue((float) $row['value'], $row['currency_code']),\n 'openDate' => $row['remotely_created_at'] ?? null,\n 'closeDate' => $row['close_date'] ?? null,\n 'stages' => [],\n 'currentPipelineId' => $row['pipeline_id'],\n 'currentStage' => [\n 'id' => $row['stage_id'],\n 'enteredAt' => $row['stage_updated_at'],\n ],\n 'currentStageUpdatedAt' => $row['stage_updated_at'],\n 'isClosed' => (bool) $row['is_closed'],\n 'isWon' => (bool) $row['is_won'],\n ];\n\n if (isset($row['owner_uuid'])) {\n $data['owner'] = [\n 'uuid' => RequiresUUID::toNormal($row['owner_uuid']),\n 'name' => $row['owner_name'],\n 'photoUrl' => $row['owner_photo'] === null\n ? null\n : client_cdn($row['owner_photo'], $team),\n 'id' => $row['owner_id'],\n 'job' => $row['owner_job'],\n ];\n }\n\n $result[(int) $row['opp_id']] = $data;\n }\n\n return $this->hydrateStages($result);\n }\n\n private function getSearchSelectAndWhereClauses(QueryBuilder $queryBuilder): QueryBuilder\n {\n $qb = clone $queryBuilder;\n $qb->leftJoin('usr', 'job_titles', 'jt', 'usr.job_title_id = jt.id');\n\n $qb\n ->select(...[\n 'opp.id as opp_id',\n 'opp.uuid',\n 'opp.name',\n 'opp.value',\n 'opp.currency_code',\n 'opp.close_date',\n 'opp.remotely_created_at',\n 'opp.is_closed',\n 'opp.is_won',\n ])\n ->addSelect(...[\n 'usr.uuid as owner_uuid',\n 'usr.name AS owner_name',\n 'usr.photo_path as owner_photo',\n 'usr.id AS owner_id',\n 'jt.name as owner_job',\n ])\n ->addSelect('opp.stage_id', 'opp.stage_updated_at')\n ->addSelect(...[\n 'acc.name AS acc_name',\n 'acc.is_internal as acc_is_internal',\n 'opp.stage_updated_at',\n 'acc.crm_provider_id AS acc_provider_id',\n 'opp.crm_provider_id AS opp_provider_id',\n ])\n ->addSelect('rt.business_process_id AS pipeline_id')\n\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not display deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'));\n\n return $qb;\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws SocialAccountTokenInvalidException\n */\n private function getCrmService(Team $team): ServiceInterface\n {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n $crmService->setConfiguration($team->crm);\n if ($crmService instanceof UrlGeneratorInterface) {\n $crmService->setCrmUrlGenerator($team->crm);\n }\n\n return $crmService;\n }\n\n /**\n *\n * @return Generator<DealData>\n */\n public function getForecastData(DealsFilter $filter): Generator\n {\n $opportunities = DB::query()\n ->select([\n 'o.value',\n 'o.close_date',\n 'o.currency_code',\n 'o.is_won',\n 'o.is_closed',\n 'o.probability',\n 'o.forecast_category',\n ])\n ->from('opportunities', 'o')\n ->join('users', 'users.id', '=', 'o.user_id')\n ->join('groups', 'groups.id', '=', 'users.group_id')\n ->where('users.team_id', $filter->getTeam()->getId())\n ->where('o.close_date', '>=', $filter->getStartDate())\n ->where('o.close_date', '<=', $filter->getEndDate())\n ->where('o.currency_code', $filter->getCurrency())\n ->where('o.deleted_at', '=', null)\n ;\n\n $userUuidList = $filter->getUserUuidList();\n if (! empty($userUuidList)) {\n $userUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $userUuidList);\n\n $opportunities->whereIn('users.uuid', $userUuidList);\n }\n\n $groupUuidList = $filter->getGroupUuidList();\n if (! empty($groupUuidList)) {\n $groupUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $groupUuidList);\n\n $opportunities->whereIn('groups.uuid', $groupUuidList);\n }\n\n foreach ($opportunities->cursor() as $row) {\n yield new DealData(\n (float) $row->value,\n $row->close_date,\n ! empty($row->is_won),\n ! empty($row->is_closed),\n $row->probability ?: 0,\n $row->forecast_category ?: '',\n );\n }\n }\n\n public function getUserOpportunitySubscriptions(User $user, array $opportunityIds): Collection\n {\n return $user->subscriptionSets()\n ->where(static function (Eloquent\\Builder $query): void {\n $query\n ->whereNull('expired_at')\n ->orWhere('expired_at', '>=', now());\n })\n ->join('activity_subscriptions', function (Builder $join) use ($opportunityIds) {\n $join\n ->on('subscription_set_id', '=', 'activity_subscription_sets.id');\n $join\n ->where('followable_type', Models\\Activity\\Subscription::FOLLOWABLE_TYPE_OPPORTUNITY)\n ->whereIn('followable_id', $opportunityIds);\n })\n ->pluck('followable_id');\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\DealInsights;\n\nuse Doctrine\\DBAL\\Connection;\nuse Generator;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Facades\\DB;\nuse Jiminny\\Component\\DealInsights\\Forecast\\DealData;\nuse Jiminny\\Component\\DealInsights\\Forecast\\DealsFilter;\nuse Jiminny\\Component\\DealInsights\\QueryBuilder\\QueryBuilder;\nuse Jiminny\\Component\\DealInsights\\QueryBuilder\\Visitor\\QueryBuilderVisitorInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Models;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\Utils\\UrlGeneratorInterface;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Database\\Eloquent;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\n\nclass DealsRepository implements DealsRepositoryInterface\n{\n private Connection $connection;\n\n private ProviderRegistry $providerRegistry;\n\n /**\n * @var QueryBuilderVisitorInterface[]\n */\n private array $visitors = [];\n\n /**\n * @param QueryBuilderVisitorInterface[] $visitors\n */\n public function __construct(Connection $connection, ProviderRegistry $crmProviderRegistry, array $visitors = [])\n {\n $this->connection = $connection;\n $this->providerRegistry = $crmProviderRegistry;\n\n foreach ($visitors as $visitor) {\n $this->visitors[$visitor->getIdentifier()] = $visitor;\n }\n }\n\n public function getDeals(CriteriaInterface $criteria): array\n {\n $context = $criteria->getContext();\n $team = $context->getTeam();\n $crmService = $this->getCrmService($team);\n\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);\n $qb = $this->getSearchSelectAndWhereClauses($qb);\n\n $this->visit($qb, $criteria);\n\n return $this->execute($team, $crmService, $qb);\n }\n\n public function getDeal(Team $team, int $id): array\n {\n $crmService = $this->getCrmService($team);\n\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);\n $qb = $this->getSearchSelectAndWhereClauses($qb);\n $qb->andWhere('opp.id = :id')->setParameter('id', $id);\n\n return $this->execute($team, $crmService, $qb);\n }\n\n public function getCrmFieldData(array $crmFields, int $crmId, array $opportunityIds = [])\n {\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('f.id', 'f.crm_provider_id AS field_name', 'f.label', 'fd.object_id AS dealId', 'fd.value')\n ->from('crm_fields', 'f')\n ->join('f', 'crm_field_data', 'fd', 'fd.crm_field_id = f.id')\n ->where('f.crm_configuration_id = :crm')\n ->andWhere('f.object_type = :type')\n ->andWhere('fd.object_id IN (' . implode(',', $opportunityIds) . ')')\n ->orderBy('fd.object_id', 'ASC')\n ->addOrderBy('fd.updated_at', 'ASC')\n\n ->setParameter('type', Field::OBJECT_OPPORTUNITY)\n ->setParameter('crm', $crmId)\n ;\n\n if (! empty($crmFields)) {\n $fields = array_map(fn ($value): string => '\"' . $value . '\"', $crmFields);\n $qb->andWhere('f.crm_provider_id IN (' . implode(',', $fields) . ')');\n }\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n public function getTotalsInDefaultCurrency(CriteriaInterface $criteria): array\n {\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);\n\n $qb\n ->select('SUM(opp.value) as total')\n ->addSelect('count(*) as `count`')\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'))\n ;\n\n $this->visit($qb, $criteria);\n\n return $qb->executeQuery()->fetchAssociative();\n }\n\n public function getTotals(CriteriaInterface $criteria, string $defaultCurrency): array\n {\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);\n\n $qb\n ->select('COALESCE(opp.currency_code, \"' . $defaultCurrency . '\") AS currency')\n ->addSelect('SUM(opp.value) as total')\n ->addSelect('count(*) as `count`')\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'))\n ->groupBy('currency')\n ;\n\n $this->visit($qb, $criteria);\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n public function getDealActivities(CriteriaInterface $criteria): array\n {\n $qb = Activity::with(['participants', 'user'])\n ->where('opportunity_id', $criteria->getOpportunityId())\n ->whereDate('actual_start_time', '>=', $criteria->getPeriod()->getStartDate())\n ->whereDate('actual_start_time', '<=', $criteria->getPeriod()->getEndDate())\n ->orderBy($criteria->getSortBy(), $criteria->getSortDirection())\n ;\n\n // Should we filter activities by criteria? It's intended to filter deals.\n\n return $qb->get()->all();\n }\n\n public function getStages(CriteriaInterface $criteria): array\n {\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('id', 'label', 'sequence')\n ->from('stages', 's')\n ->where('crm_configuration_id = :crm_configuration_id')\n ->andWhere('type = :type')\n ->orderBy('sequence', 'ASC')\n\n ->setParameter('crm_configuration_id', $criteria->getContext()->getTeam()->getCrmConfiguration()->getId())\n ->setParameter('type', Stage::TYPE_OPPORTUNITY);\n\n $result = [];\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $result[$row['id']] = [\n 'label' => $row['label'],\n 'sequence' => $row['sequence'],\n ];\n }\n\n return $result;\n }\n\n public function getConfigurationStages(Configuration $configuration): Collection\n {\n return $configuration\n ->stages()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get();\n }\n\n public function getPipelineData(Configuration $crm): array\n {\n $qb = new QueryBuilder($this->connection);\n $provider = $crm->provider;\n\n $qb\n ->select('s.label', 's.crm_provider_id', 's.sequence', 'bps.business_process_id AS pipeline_id')\n ->from('stages', 's')\n ->join('s', 'business_process_stages', 'bps', 's.id=bps.stage_id')\n ->where('s.crm_configuration_id = :crm_configuration_id')\n ->andWhere('s.type = :type')\n ->orderBy('bps.business_process_id', 'ASC')\n ->addOrderBy('s.sequence', 'ASC')\n\n ->setParameter('crm_configuration_id', $crm->id)\n ->setParameter('type', Stage::TYPE_OPPORTUNITY)\n ;\n\n $result = [];\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $value = $provider === Configuration::PROVIDER_SALESFORCE ? $row['label'] : $row['crm_provider_id'];\n $result[$row['pipeline_id']][] = [\n 'value' => $value,\n 'label' => $row['label'],\n 'sequence' => $row['sequence'],\n ];\n }\n\n return $result;\n }\n\n private function createQueryBuilder(string $realm): QueryBuilder\n {\n return (new QueryBuilder($this->connection))\n ->setRealm($realm)\n ->from('opportunities', 'opp')\n ->leftJoin('opp', 'record_types', 'rt', 'opp.record_type_id = rt.id')\n ->leftJoin('opp', 'users', 'usr', 'opp.user_id = usr.id')\n ->leftJoin('opp', 'accounts', 'acc', 'opp.account_id = acc.id')\n ;\n }\n\n /**\n * Applies all applicable visitors and returns the IDs of the executed ones\n *\n * @return string[]\n */\n private function visit(QueryBuilder $queryBuilder, CriteriaInterface $criteria): array\n {\n $queryVisitors = [];\n\n foreach ($this->visitors as $visitor) {\n if ($visitor->isSatisfiedBy($criteria, $queryBuilder->getRealm())) {\n $visitor->visit($queryBuilder, $criteria);\n\n $queryVisitors[] = $visitor->getIdentifier();\n }\n }\n\n return $queryVisitors;\n }\n\n private function hydrateStages(array $deals): array\n {\n foreach ($this->fetchStages(array_keys($deals)) as $stage) {\n $oppId = (int) $stage['opportunity_id'];\n\n if (! isset($deals[$oppId])) {\n continue; // or throw??!\n }\n\n $deals[$oppId]['stages'][] = [\n 'id' => $stage['stage_id'],\n 'name' => $stage['label'],\n 'enteredAt' => $stage['created_at'],\n ];\n }\n\n return $deals;\n }\n\n /**\n * @param int[] $dealIds\n */\n private function fetchStages(array $dealIds): array\n {\n if (empty($dealIds)) {\n return [];\n }\n\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('os.opportunity_id', 's.id AS stage_id', 's.label', 's.created_at')\n ->from('opportunity_stages', 'os')\n ->leftJoin('os', 'stages', 's', 'os.stage_id=s.id')\n ->where($qb->expr()->in('os.opportunity_id', $dealIds))\n ->orderBy('os.opportunity_id', 'ASC')\n ->addOrderBy('s.created_at', 'ASC')\n ;\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n private function execute(Team $team, ServiceInterface $crmService, QueryBuilder $qb): array\n {\n $result = [];\n\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $data = [\n 'uuid' => RequiresUUID::toNormal($row['uuid']),\n 'name' => $row['name'],\n 'url' => $crmService->generateProviderUrl($row['opp_provider_id'], 'opportunity'),\n 'account' => [\n 'name' => $row['acc_name'],\n 'url' => $crmService->generateProviderUrl(\n providerId: $row['acc_provider_id'],\n objectType: $row['acc_is_internal'] ? 'internal-account' : 'account'\n ),\n ],\n 'owner' => null,\n 'rawValue' => [\n 'amount' => (float) $row['value'],\n 'currency' => $row['currency_code'],\n ],\n 'value' => formatOpportunityValue((float) $row['value'], $row['currency_code']),\n 'openDate' => $row['remotely_created_at'] ?? null,\n 'closeDate' => $row['close_date'] ?? null,\n 'stages' => [],\n 'currentPipelineId' => $row['pipeline_id'],\n 'currentStage' => [\n 'id' => $row['stage_id'],\n 'enteredAt' => $row['stage_updated_at'],\n ],\n 'currentStageUpdatedAt' => $row['stage_updated_at'],\n 'isClosed' => (bool) $row['is_closed'],\n 'isWon' => (bool) $row['is_won'],\n ];\n\n if (isset($row['owner_uuid'])) {\n $data['owner'] = [\n 'uuid' => RequiresUUID::toNormal($row['owner_uuid']),\n 'name' => $row['owner_name'],\n 'photoUrl' => $row['owner_photo'] === null\n ? null\n : client_cdn($row['owner_photo'], $team),\n 'id' => $row['owner_id'],\n 'job' => $row['owner_job'],\n ];\n }\n\n $result[(int) $row['opp_id']] = $data;\n }\n\n return $this->hydrateStages($result);\n }\n\n private function getSearchSelectAndWhereClauses(QueryBuilder $queryBuilder): QueryBuilder\n {\n $qb = clone $queryBuilder;\n $qb->leftJoin('usr', 'job_titles', 'jt', 'usr.job_title_id = jt.id');\n\n $qb\n ->select(...[\n 'opp.id as opp_id',\n 'opp.uuid',\n 'opp.name',\n 'opp.value',\n 'opp.currency_code',\n 'opp.close_date',\n 'opp.remotely_created_at',\n 'opp.is_closed',\n 'opp.is_won',\n ])\n ->addSelect(...[\n 'usr.uuid as owner_uuid',\n 'usr.name AS owner_name',\n 'usr.photo_path as owner_photo',\n 'usr.id AS owner_id',\n 'jt.name as owner_job',\n ])\n ->addSelect('opp.stage_id', 'opp.stage_updated_at')\n ->addSelect(...[\n 'acc.name AS acc_name',\n 'acc.is_internal as acc_is_internal',\n 'opp.stage_updated_at',\n 'acc.crm_provider_id AS acc_provider_id',\n 'opp.crm_provider_id AS opp_provider_id',\n ])\n ->addSelect('rt.business_process_id AS pipeline_id')\n\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not display deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'));\n\n return $qb;\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws SocialAccountTokenInvalidException\n */\n private function getCrmService(Team $team): ServiceInterface\n {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n $crmService->setConfiguration($team->crm);\n if ($crmService instanceof UrlGeneratorInterface) {\n $crmService->setCrmUrlGenerator($team->crm);\n }\n\n return $crmService;\n }\n\n /**\n *\n * @return Generator<DealData>\n */\n public function getForecastData(DealsFilter $filter): Generator\n {\n $opportunities = DB::query()\n ->select([\n 'o.value',\n 'o.close_date',\n 'o.currency_code',\n 'o.is_won',\n 'o.is_closed',\n 'o.probability',\n 'o.forecast_category',\n ])\n ->from('opportunities', 'o')\n ->join('users', 'users.id', '=', 'o.user_id')\n ->join('groups', 'groups.id', '=', 'users.group_id')\n ->where('users.team_id', $filter->getTeam()->getId())\n ->where('o.close_date', '>=', $filter->getStartDate())\n ->where('o.close_date', '<=', $filter->getEndDate())\n ->where('o.currency_code', $filter->getCurrency())\n ->where('o.deleted_at', '=', null)\n ;\n\n $userUuidList = $filter->getUserUuidList();\n if (! empty($userUuidList)) {\n $userUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $userUuidList);\n\n $opportunities->whereIn('users.uuid', $userUuidList);\n }\n\n $groupUuidList = $filter->getGroupUuidList();\n if (! empty($groupUuidList)) {\n $groupUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $groupUuidList);\n\n $opportunities->whereIn('groups.uuid', $groupUuidList);\n }\n\n foreach ($opportunities->cursor() as $row) {\n yield new DealData(\n (float) $row->value,\n $row->close_date,\n ! empty($row->is_won),\n ! empty($row->is_closed),\n $row->probability ?: 0,\n $row->forecast_category ?: '',\n );\n }\n }\n\n public function getUserOpportunitySubscriptions(User $user, array $opportunityIds): Collection\n {\n return $user->subscriptionSets()\n ->where(static function (Eloquent\\Builder $query): void {\n $query\n ->whereNull('expired_at')\n ->orWhere('expired_at', '>=', now());\n })\n ->join('activity_subscriptions', function (Builder $join) use ($opportunityIds) {\n $join\n ->on('subscription_set_id', '=', 'activity_subscription_sets.id');\n $join\n ->where('followable_type', Models\\Activity\\Subscription::FOLLOWABLE_TYPE_OPPORTUNITY)\n ->whereIn('followable_id', $opportunityIds);\n })\n ->pluck('followable_id');\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"role_description":"text"}]...
|
-1229504928616003175
|
8406718389802436924
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20157-AJ-report-not-se Project: faVsco.js, menu
JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
12
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Http\Transformers;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Collection;
use Jiminny\Component\Sidekick\SidekickService;
use Jiminny\Exceptions\ActivityProviderException;
use Jiminny\Http\Controllers\Settings\Users\Utils\UserSetting;
use Jiminny\Models\Activity\Provider;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\JobTitle;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Notification\Messengers\MsTeams;
use Jiminny\Services\UserService;
use League\Fractal\Resource;
use League\Fractal\Resource\Item;
use League\Fractal\TransformerAbstract;
class UserTransformer extends TransformerAbstract
{
protected array $availableIncludes = [
'team',
'group',
'job',
'roles',
'permissions',
];
private Container $container;
private bool $withSelfVisibility = false;
public function __construct(?Container $container = null)
{
$this->container = $container ?? app();
}
public function withSelfVisibility(): self
{
$this->withSelfVisibility = true;
return $this;
}
/**
* @throws ActivityProviderException
*
* @return array<string, mixed>
*/
public function transform(User $user): array
{
$attributes = [
'id' => $user->getUuid(),
'name' => $user->getName(),
'firstName' => $user->getFirstName(),
'photoUrl' => $user->getPhotoUrl(),
'conferenceRecordPreference' => $user->checkConferenceRecordPreference(),
'conferenceRecordInternalPreference' => $user->checkConferenceRecordInternalPreference(),
// DO NOT USE User::isCrmRequired as it is not hydrated when fetched from ES!
'crmRequired' => $user->crm_required,
'slackFollowUp' => $user->slack_follow_up,
];
// DO NOT USE User::getId as it is not hydrated when fetched from ES!
if ($this->withSelfVisibility || (auth()->check() && auth()->user()->id === $user->id)) {
$softphoneHasVoiceCapability = $user->hasSoftphoneNumberCapabilities()
&& $user->getSoftphoneNumberCapabilities()->hasVoiceCapability()
;
$conferenceSidekickOpen = $user->getConferenceSidekickOpen();
$softphoneSidekickOpen = $user->getSoftphoneSidekickOpen();
$conferenceSidekickPopupOverridden = false;
$softphoneSidekickPopupOverridden = false;
$hasSidekickEnabled = true;
if ($user->getTeam()->hasFeature(FeatureEnum::SIDEKICK_SETTINGS)) {
$sidekickService = $this->getSidekickService();
$sidekickData = $sidekickService->getSidekickSettingsForUser($user);
$conferenceSidekickOpen = $sidekickData['conferenceSettings'];
$softphoneSidekickOpen = $sidekickData['softphoneSettings'];
$conferenceSidekickPopupOverridden = $sidekickData['conferenceSidekickPopupOverridden'];
$softphoneSidekickPopupOverridden = $sidekickData['softphoneSidekickPopupOverridden'];
$hasSidekickEnabled = $sidekickData['sidekickEnabled'];
}
$userService = $this->getUserService();
$dealInsightsPeriod = $userService->getDealInsightTimelinePeriod($user);
$dataFormatCountryCode = $userService->getDateTimeCountryCode($user);
// Attributes for the user only.
$attributes += [
'conferenceJoinReminder' => $user->conference_join_reminder,
'softphoneInboundRecordPreference' => $user->checkSoftphoneInboundRecordPreference(),
'softphoneOutboundRecordPreference' => $user->checkSoftphoneOutboundRecordPreference(),
'softphoneInboundDestination' => $user->softphone_inbound_destination,
'softphoneHasVoiceCapability' => $softphoneHasVoiceCapability,
'softphoneNumber' => $user->getSoftPhoneNumber(),
'formattedSoftphoneNumber' => $user->getFormattedSoftphoneNumberAttribute(),
'email' => $user->getEmailAddress(),
'secondaryEmail' => $user->getSecondaryEmailAddress(),
'phone' => $user->phone,
'secondaryPhone' => $user->secondary_phone,
'callerId' => $user->getCallerId(),
'countryCode' => $user->getCountryCode(),
'timezone' => $user->getTimezone()->getName(),
'language' => $user->getLanguage(),
'locales' => $this->container->get(UserRepository::class)->getUserLocales($user),
'status' => $user->getStatus(),
'hash' => $user->generateHash(),
'registrationDate' => $user->created_at ? $user->created_at->toIso8601String() : null,
'notifyLiveCoaching' => $user->notify_live_coaching,
'activityLogReminder' => $user->activity_log_reminder,
'conferenceSidekickOpen' => $conferenceSidekickOpen,
'softphoneSidekickOpen' => $softphoneSidekickOpen,
'conferenceSidekickPopupOverridden' => $conferenceSidekickPopupOverridden,
'softphoneSidekickPopupOverridden' => $softphoneSidekickPopupOverridden,
'hasSidekickEnabled' => $hasSidekickEnabled,
'activityActionItems' => $user->activity_action_items,
'syncEmail' => $user->isSyncEmailEnabled(),
'syncConference' => $user->sync_conference,
'syncDialer' => $user->shouldSyncDialer(),
'needsToConfigurePhoneNumber' => $this->container
->get('onboarding_phone_decider')
->isOnboardable($user),
'shouldShowPhoneNumberField' => $this->container
->get('onboarding_phone_decider')
->shouldShowPhoneNumberField($user),
UserSetting::DEAL_INSIGHTS_TIMELINE_PERIOD => $dealInsightsPeriod,
'countryByTimezone' => $dataFormatCountryCode,
'conferenceSlug' => $user->getConferenceSlug(),
'conferenceRecordExternalOrganizerPreference' =>
$userService->isConferenceRecordExternalOrganizerPreferenceEnabled($user),
'hasGeneratedAiReports' => $this->getAutomatedReportsRepository()->countUserReports($user) > 0,
'sendEmailWhenExportLinkIsOpened' => $userService->canSendEmailWhenExportLinkIsOpened($user),
];
if ($user->softphone_debug) {
$attributes += [
'debugSoftphone' => $user->softphone_debug, // Needed?
];
}
}
if ($user->getTeam()->getNotificationProvider() === Team::NOTIFICATION_PROVIDER_MSTEAMS) {
$socialAccountMS = $user->getSocialAccount(Team::CALENDAR_PROVIDER_OFFICE);
$state = $socialAccountMS !== null
? str_contains($socialAccountMS->auth_scope, MsTeams::SCOPE_CHAT_CREATE)
: null;
$attributes['integrations']['office'] = [
'displayName' => 'Microsoft Teams',
'apiName' => 'microsoft-teams',
'types' => ['notification'],
'state' => $state ? Provider::STATE_INSTALLED : Provider::STATE_NOT_INSTALLED,
'logo' => cdn('img/ms-teams-logo.svg'),
'installationStrategy' => 'oauth',
];
}
return $attributes;
}
public function includeTeam(User $user): Item
{
$team = $user->getTeam();
return $this->item($team, $this->getTeamTransformer());
}
public function includeGroup(User $user): ?Item
{
$group = $user->getGroup();
if ($group === null) {
return null;
}
return $this->item($group, $this->getGroupTransformer());
}
public function includeJob(User $user): ?Item
{
$job = $user->getJobTitle();
if (! $job instanceof JobTitle) {
return null;
}
return $this->item($job, $this->getJobTitleTransformer());
}
public function includeRoles(User $user): Resource\Collection
{
/** @var Collection<int, string> $roles */
$roles = $user->roles()
->where('is_visible', true)
->pluck('name')
->toArray();
return $this->collection($roles, $this->getRoleTransformer());
}
public function includePermissions(User $user): Resource\Collection
{
$permissions = $user->allPermissions();
return $this->collection($permissions, $this->getPermissionTransformer());
}
public function includeIntegrations(User $user): Item
{
return $this->item($user, $this->getIntegrationsTransformer());
}
private function getTeamTransformer(): TransformerAbstract
{
return $this->container->get(TeamTransformer::class);
}
private function getGroupTransformer(): GroupTransformer
{
return $this->container->get(GroupTransformer::class);
}
private function getIntegrationsTransformer(): IntegrationTransformer
{
return $this->container->get(IntegrationTransformer::class);
}
private function getPermissionTransformer(): PermissionTransformer
{
return $this->container->get(PermissionTransformer::class);
}
private function getRoleTransformer(): RoleTransformer
{
return $this->container->get(RoleTransformer::class);
}
private function getJobTitleTransformer(): JobTitleTransformer
{
return $this->container->get(JobTitleTransformer::class);
}
private function getSidekickService(): SidekickService
{
/** @var SidekickService */
return $this->container->get(SidekickService::class);
}
private function getUserService(): UserService
{
/** @var UserService */
return $this->container->get(UserService::class);
}
private function getAutomatedReportsRepository(): AutomatedReportsRepository
{
/** @var AutomatedReportsRepository */
return $this->container->get(AutomatedReportsRepository::class);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
36
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\DealInsights;
use Doctrine\DBAL\Connection;
use Generator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Jiminny\Component\DealInsights\Forecast\DealData;
use Jiminny\Component\DealInsights\Forecast\DealsFilter;
use Jiminny\Component\DealInsights\QueryBuilder\QueryBuilder;
use Jiminny\Component\DealInsights\QueryBuilder\Visitor\QueryBuilderVisitorInterface;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Stage;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Models;
use Jiminny\Services\Crm\IntegrationApp\DTO\Utils\UrlGeneratorInterface;
use Jiminny\Services\Crm\ProviderRegistry;
use Jiminny\Traits\RequiresUUID;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Eloquent;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class DealsRepository implements DealsRepositoryInterface
{
private Connection $connection;
private ProviderRegistry $providerRegistry;
/**
* @var QueryBuilderVisitorInterface[]
*/
private array $visitors = [];
/**
* @param QueryBuilderVisitorInterface[] $visitors
*/
public function __construct(Connection $connection, ProviderRegistry $crmProviderRegistry, array $visitors = [])
{
$this->connection = $connection;
$this->providerRegistry = $crmProviderRegistry;
foreach ($visitors as $visitor) {
$this->visitors[$visitor->getIdentifier()] = $visitor;
}
}
public function getDeals(CriteriaInterface $criteria): array
{
$context = $criteria->getContext();
$team = $context->getTeam();
$crmService = $this->getCrmService($team);
$qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);
$qb = $this->getSearchSelectAndWhereClauses($qb);
$this->visit($qb, $criteria);
return $this->execute($team, $crmService, $qb);
}
public function getDeal(Team $team, int $id): array
{
$crmService = $this->getCrmService($team);
$qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);
$qb = $this->getSearchSelectAndWhereClauses($qb);
$qb->andWhere('opp.id = :id')->setParameter('id', $id);
return $this->execute($team, $crmService, $qb);
}
public function getCrmFieldData(array $crmFields, int $crmId, array $opportunityIds = [])
{
$qb = new QueryBuilder($this->connection);
$qb
->select('f.id', 'f.crm_provider_id AS field_name', 'f.label', 'fd.object_id AS dealId', 'fd.value')
->from('crm_fields', 'f')
->join('f', 'crm_field_data', 'fd', 'fd.crm_field_id = f.id')
->where('f.crm_configuration_id = :crm')
->andWhere('f.object_type = :type')
->andWhere('fd.object_id IN (' . implode(',', $opportunityIds) . ')')
->orderBy('fd.object_id', 'ASC')
->addOrderBy('fd.updated_at', 'ASC')
->setParameter('type', Field::OBJECT_OPPORTUNITY)
->setParameter('crm', $crmId)
;
if (! empty($crmFields)) {
$fields = array_map(fn ($value): string => '"' . $value . '"', $crmFields);
$qb->andWhere('f.crm_provider_id IN (' . implode(',', $fields) . ')');
}
return $qb->executeQuery()->fetchAllAssociative();
}
public function getTotalsInDefaultCurrency(CriteriaInterface $criteria): array
{
$qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);
$qb
->select('SUM(opp.value) as total')
->addSelect('count(*) as `count`')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'))
;
$this->visit($qb, $criteria);
return $qb->executeQuery()->fetchAssociative();
}
public function getTotals(CriteriaInterface $criteria, string $defaultCurrency): array
{
$qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);
$qb
->select('COALESCE(opp.currency_code, "' . $defaultCurrency . '") AS currency')
->addSelect('SUM(opp.value) as total')
->addSelect('count(*) as `count`')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'))
->groupBy('currency')
;
$this->visit($qb, $criteria);
return $qb->executeQuery()->fetchAllAssociative();
}
public function getDealActivities(CriteriaInterface $criteria): array
{
$qb = Activity::with(['participants', 'user'])
->where('opportunity_id', $criteria->getOpportunityId())
->whereDate('actual_start_time', '>=', $criteria->getPeriod()->getStartDate())
->whereDate('actual_start_time', '<=', $criteria->getPeriod()->getEndDate())
->orderBy($criteria->getSortBy(), $criteria->getSortDirection())
;
// Should we filter activities by criteria? It's intended to filter deals.
return $qb->get()->all();
}
public function getStages(CriteriaInterface $criteria): array
{
$qb = new QueryBuilder($this->connection);
$qb
->select('id', 'label', 'sequence')
->from('stages', 's')
->where('crm_configuration_id = :crm_configuration_id')
->andWhere('type = :type')
->orderBy('sequence', 'ASC')
->setParameter('crm_configuration_id', $criteria->getContext()->getTeam()->getCrmConfiguration()->getId())
->setParameter('type', Stage::TYPE_OPPORTUNITY);
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$result[$row['id']] = [
'label' => $row['label'],
'sequence' => $row['sequence'],
];
}
return $result;
}
public function getConfigurationStages(Configuration $configuration): Collection
{
return $configuration
->stages()
->where('type', Stage::TYPE_OPPORTUNITY)
->get();
}
public function getPipelineData(Configuration $crm): array
{
$qb = new QueryBuilder($this->connection);
$provider = $crm->provider;
$qb
->select('s.label', 's.crm_provider_id', 's.sequence', 'bps.business_process_id AS pipeline_id')
->from('stages', 's')
->join('s', 'business_process_stages', 'bps', 's.id=bps.stage_id')
->where('s.crm_configuration_id = :crm_configuration_id')
->andWhere('s.type = :type')
->orderBy('bps.business_process_id', 'ASC')
->addOrderBy('s.sequence', 'ASC')
->setParameter('crm_configuration_id', $crm->id)
->setParameter('type', Stage::TYPE_OPPORTUNITY)
;
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$value = $provider === Configuration::PROVIDER_SALESFORCE ? $row['label'] : $row['crm_provider_id'];
$result[$row['pipeline_id']][] = [
'value' => $value,
'label' => $row['label'],
'sequence' => $row['sequence'],
];
}
return $result;
}
private function createQueryBuilder(string $realm): QueryBuilder
{
return (new QueryBuilder($this->connection))
->setRealm($realm)
->from('opportunities', 'opp')
->leftJoin('opp', 'record_types', 'rt', 'opp.record_type_id = rt.id')
->leftJoin('opp', 'users', 'usr', 'opp.user_id = usr.id')
->leftJoin('opp', 'accounts', 'acc', 'opp.account_id = acc.id')
;
}
/**
* Applies all applicable visitors and returns the IDs of the executed ones
*
* @return string[]
*/
private function visit(QueryBuilder $queryBuilder, CriteriaInterface $criteria): array
{
$queryVisitors = [];
foreach ($this->visitors as $visitor) {
if ($visitor->isSatisfiedBy($criteria, $queryBuilder->getRealm())) {
$visitor->visit($queryBuilder, $criteria);
$queryVisitors[] = $visitor->getIdentifier();
}
}
return $queryVisitors;
}
private function hydrateStages(array $deals): array
{
foreach ($this->fetchStages(array_keys($deals)) as $stage) {
$oppId = (int) $stage['opportunity_id'];
if (! isset($deals[$oppId])) {
continue; // or throw??!
}
$deals[$oppId]['stages'][] = [
'id' => $stage['stage_id'],
'name' => $stage['label'],
'enteredAt' => $stage['created_at'],
];
}
return $deals;
}
/**
* @param int[] $dealIds
*/
private function fetchStages(array $dealIds): array
{
if (empty($dealIds)) {
return [];
}
$qb = new QueryBuilder($this->connection);
$qb
->select('os.opportunity_id', 's.id AS stage_id', 's.label', 's.created_at')
->from('opportunity_stages', 'os')
->leftJoin('os', 'stages', 's', 'os.stage_id=s.id')
->where($qb->expr()->in('os.opportunity_id', $dealIds))
->orderBy('os.opportunity_id', 'ASC')
->addOrderBy('s.created_at', 'ASC')
;
return $qb->executeQuery()->fetchAllAssociative();
}
private function execute(Team $team, ServiceInterface $crmService, QueryBuilder $qb): array
{
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$data = [
'uuid' => RequiresUUID::toNormal($row['uuid']),
'name' => $row['name'],
'url' => $crmService->generateProviderUrl($row['opp_provider_id'], 'opportunity'),
'account' => [
'name' => $row['acc_name'],
'url' => $crmService->generateProviderUrl(
providerId: $row['acc_provider_id'],
objectType: $row['acc_is_internal'] ? 'internal-account' : 'account'
),
],
'owner' => null,
'rawValue' => [
'amount' => (float) $row['value'],
'currency' => $row['currency_code'],
],
'value' => formatOpportunityValue((float) $row['value'], $row['currency_code']),
'openDate' => $row['remotely_created_at'] ?? null,
'closeDate' => $row['close_date'] ?? null,
'stages' => [],
'currentPipelineId' => $row['pipeline_id'],
'currentStage' => [
'id' => $row['stage_id'],
'enteredAt' => $row['stage_updated_at'],
],
'currentStageUpdatedAt' => $row['stage_updated_at'],
'isClosed' => (bool) $row['is_closed'],
'isWon' => (bool) $row['is_won'],
];
if (isset($row['owner_uuid'])) {
$data['owner'] = [
'uuid' => RequiresUUID::toNormal($row['owner_uuid']),
'name' => $row['owner_name'],
'photoUrl' => $row['owner_photo'] === null
? null
: client_cdn($row['owner_photo'], $team),
'id' => $row['owner_id'],
'job' => $row['owner_job'],
];
}
$result[(int) $row['opp_id']] = $data;
}
return $this->hydrateStages($result);
}
private function getSearchSelectAndWhereClauses(QueryBuilder $queryBuilder): QueryBuilder
{
$qb = clone $queryBuilder;
$qb->leftJoin('usr', 'job_titles', 'jt', 'usr.job_title_id = jt.id');
$qb
->select(...[
'opp.id as opp_id',
'opp.uuid',
'opp.name',
'opp.value',
'opp.currency_code',
'opp.close_date',
'opp.remotely_created_at',
'opp.is_closed',
'opp.is_won',
])
->addSelect(...[
'usr.uuid as owner_uuid',
'usr.name AS owner_name',
'usr.photo_path as owner_photo',
'usr.id AS owner_id',
'jt.name as owner_job',
])
->addSelect('opp.stage_id', 'opp.stage_updated_at')
->addSelect(...[
'acc.name AS acc_name',
'acc.is_internal as acc_is_internal',
'opp.stage_updated_at',
'acc.crm_provider_id AS acc_provider_id',
'opp.crm_provider_id AS opp_provider_id',
])
->addSelect('rt.business_process_id AS pipeline_id')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not display deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'));
return $qb;
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws SocialAccountTokenInvalidException
*/
private function getCrmService(Team $team): ServiceInterface
{
$crmService = $this->providerRegistry->get($team->crm->provider);
$crmService->setConfiguration($team->crm);
if ($crmService instanceof UrlGeneratorInterface) {
$crmService->setCrmUrlGenerator($team->crm);
}
return $crmService;
}
/**
*
* @return Generator<DealData>
*/
public function getForecastData(DealsFilter $filter): Generator
{
$opportunities = DB::query()
->select([
'o.value',
'o.close_date',
'o.currency_code',
'o.is_won',
'o.is_closed',
'o.probability',
'o.forecast_category',
])
->from('opportunities', 'o')
->join('users', 'users.id', '=', 'o.user_id')
->join('groups', 'groups.id', '=', 'users.group_id')
->where('users.team_id', $filter->getTeam()->getId())
->where('o.close_date', '>=', $filter->getStartDate())
->where('o.close_date', '<=', $filter->getEndDate())
->where('o.currency_code', $filter->getCurrency())
->where('o.deleted_at', '=', null)
;
$userUuidList = $filter->getUserUuidList();
if (! empty($userUuidList)) {
$userUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $userUuidList);
$opportunities->whereIn('users.uuid', $userUuidList);
}
$groupUuidList = $filter->getGroupUuidList();
if (! empty($groupUuidList)) {
$groupUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $groupUuidList);
$opportunities->whereIn('groups.uuid', $groupUuidList);
}
foreach ($opportunities->cursor() as $row) {
yield new DealData(
(float) $row->value,
$row->close_date,
! empty($row->is_won),
! empty($row->is_closed),
$row->probability ?: 0,
$row->forecast_category ?: '',
);
}
}
public function getUserOpportunitySubscriptions(User $user, array $opportunityIds): Collection
{
return $user->subscriptionSets()
->where(static function (Eloquent\Builder $query): void {
$query
->whereNull('expired_at')
->orWhere('expired_at', '>=', now());
})
->join('activity_subscriptions', function (Builder $join) use ($opportunityIds) {
$join
->on('subscription_set_id', '=', 'activity_subscription_sets.id');
$join
->where('followable_type', Models\Activity\Subscription::FOLLOWABLE_TYPE_OPPORTUNITY)
->whereIn('followable_id', $opportunityIds);
})
->pluck('followable_id');
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class...
|
NULL
|
|
72870
|
1779
|
10
|
2026-04-23T06:20:21.419002+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-23/1776 /Users/lukas/.screenpipe/data/data/2026-04-23/1776925221419_m2.jpg...
|
PhpStorm
|
faVsco.js – UserTransformer.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20157-AJ-report-not-se Project: faVsco.js, menu
JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
12
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Http\Transformers;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Collection;
use Jiminny\Component\Sidekick\SidekickService;
use Jiminny\Exceptions\ActivityProviderException;
use Jiminny\Http\Controllers\Settings\Users\Utils\UserSetting;
use Jiminny\Models\Activity\Provider;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\JobTitle;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Notification\Messengers\MsTeams;
use Jiminny\Services\UserService;
use League\Fractal\Resource;
use League\Fractal\Resource\Item;
use League\Fractal\TransformerAbstract;
class UserTransformer extends TransformerAbstract
{
protected array $availableIncludes = [
'team',
'group',
'job',
'roles',
'permissions',
];
private Container $container;
private bool $withSelfVisibility = false;
public function __construct(?Container $container = null)
{
$this->container = $container ?? app();
}
public function withSelfVisibility(): self
{
$this->withSelfVisibility = true;
return $this;
}
/**
* @throws ActivityProviderException
*
* @return array<string, mixed>
*/
public function transform(User $user): array
{
$attributes = [
'id' => $user->getUuid(),
'name' => $user->getName(),
'firstName' => $user->getFirstName(),
'photoUrl' => $user->getPhotoUrl(),
'conferenceRecordPreference' => $user->checkConferenceRecordPreference(),
'conferenceRecordInternalPreference' => $user->checkConferenceRecordInternalPreference(),
// DO NOT USE User::isCrmRequired as it is not hydrated when fetched from ES!
'crmRequired' => $user->crm_required,
'slackFollowUp' => $user->slack_follow_up,
];
// DO NOT USE User::getId as it is not hydrated when fetched from ES!
if ($this->withSelfVisibility || (auth()->check() && auth()->user()->id === $user->id)) {
$softphoneHasVoiceCapability = $user->hasSoftphoneNumberCapabilities()
&& $user->getSoftphoneNumberCapabilities()->hasVoiceCapability()
;
$conferenceSidekickOpen = $user->getConferenceSidekickOpen();
$softphoneSidekickOpen = $user->getSoftphoneSidekickOpen();
$conferenceSidekickPopupOverridden = false;
$softphoneSidekickPopupOverridden = false;
$hasSidekickEnabled = true;
if ($user->getTeam()->hasFeature(FeatureEnum::SIDEKICK_SETTINGS)) {
$sidekickService = $this->getSidekickService();
$sidekickData = $sidekickService->getSidekickSettingsForUser($user);
$conferenceSidekickOpen = $sidekickData['conferenceSettings'];
$softphoneSidekickOpen = $sidekickData['softphoneSettings'];
$conferenceSidekickPopupOverridden = $sidekickData['conferenceSidekickPopupOverridden'];
$softphoneSidekickPopupOverridden = $sidekickData['softphoneSidekickPopupOverridden'];
$hasSidekickEnabled = $sidekickData['sidekickEnabled'];
}
$userService = $this->getUserService();
$dealInsightsPeriod = $userService->getDealInsightTimelinePeriod($user);
$dataFormatCountryCode = $userService->getDateTimeCountryCode($user);
// Attributes for the user only.
$attributes += [
'conferenceJoinReminder' => $user->conference_join_reminder,
'softphoneInboundRecordPreference' => $user->checkSoftphoneInboundRecordPreference(),
'softphoneOutboundRecordPreference' => $user->checkSoftphoneOutboundRecordPreference(),
'softphoneInboundDestination' => $user->softphone_inbound_destination,
'softphoneHasVoiceCapability' => $softphoneHasVoiceCapability,
'softphoneNumber' => $user->getSoftPhoneNumber(),
'formattedSoftphoneNumber' => $user->getFormattedSoftphoneNumberAttribute(),
'email' => $user->getEmailAddress(),
'secondaryEmail' => $user->getSecondaryEmailAddress(),
'phone' => $user->phone,
'secondaryPhone' => $user->secondary_phone,
'callerId' => $user->getCallerId(),
'countryCode' => $user->getCountryCode(),
'timezone' => $user->getTimezone()->getName(),
'language' => $user->getLanguage(),
'locales' => $this->container->get(UserRepository::class)->getUserLocales($user),
'status' => $user->getStatus(),
'hash' => $user->generateHash(),
'registrationDate' => $user->created_at ? $user->created_at->toIso8601String() : null,
'notifyLiveCoaching' => $user->notify_live_coaching,
'activityLogReminder' => $user->activity_log_reminder,
'conferenceSidekickOpen' => $conferenceSidekickOpen,
'softphoneSidekickOpen' => $softphoneSidekickOpen,
'conferenceSidekickPopupOverridden' => $conferenceSidekickPopupOverridden,
'softphoneSidekickPopupOverridden' => $softphoneSidekickPopupOverridden,
'hasSidekickEnabled' => $hasSidekickEnabled,
'activityActionItems' => $user->activity_action_items,
'syncEmail' => $user->isSyncEmailEnabled(),
'syncConference' => $user->sync_conference,
'syncDialer' => $user->shouldSyncDialer(),
'needsToConfigurePhoneNumber' => $this->container
->get('onboarding_phone_decider')
->isOnboardable($user),
'shouldShowPhoneNumberField' => $this->container
->get('onboarding_phone_decider')
->shouldShowPhoneNumberField($user),
UserSetting::DEAL_INSIGHTS_TIMELINE_PERIOD => $dealInsightsPeriod,
'countryByTimezone' => $dataFormatCountryCode,
'conferenceSlug' => $user->getConferenceSlug(),
'conferenceRecordExternalOrganizerPreference' =>
$userService->isConferenceRecordExternalOrganizerPreferenceEnabled($user),
'hasGeneratedAiReports' => $this->getAutomatedReportsRepository()->countUserReports($user) > 0,
'sendEmailWhenExportLinkIsOpened' => $userService->canSendEmailWhenExportLinkIsOpened($user),
];
if ($user->softphone_debug) {
$attributes += [
'debugSoftphone' => $user->softphone_debug, // Needed?
];
}
}
if ($user->getTeam()->getNotificationProvider() === Team::NOTIFICATION_PROVIDER_MSTEAMS) {
$socialAccountMS = $user->getSocialAccount(Team::CALENDAR_PROVIDER_OFFICE);
$state = $socialAccountMS !== null
? str_contains($socialAccountMS->auth_scope, MsTeams::SCOPE_CHAT_CREATE)
: null;
$attributes['integrations']['office'] = [
'displayName' => 'Microsoft Teams',
'apiName' => 'microsoft-teams',
'types' => ['notification'],
'state' => $state ? Provider::STATE_INSTALLED : Provider::STATE_NOT_INSTALLED,
'logo' => cdn('img/ms-teams-logo.svg'),
'installationStrategy' => 'oauth',
];
}
return $attributes;
}
public function includeTeam(User $user): Item
{
$team = $user->getTeam();
return $this->item($team, $this->getTeamTransformer());
}
public function includeGroup(User $user): ?Item
{
$group = $user->getGroup();
if ($group === null) {
return null;
}
return $this->item($group, $this->getGroupTransformer());
}
public function includeJob(User $user): ?Item
{
$job = $user->getJobTitle();
if (! $job instanceof JobTitle) {
return null;
}
return $this->item($job, $this->getJobTitleTransformer());
}
public function includeRoles(User $user): Resource\Collection
{
/** @var Collection<int, string> $roles */
$roles = $user->roles()
->where('is_visible', true)
->pluck('name')
->toArray();
return $this->collection($roles, $this->getRoleTransformer());
}
public function includePermissions(User $user): Resource\Collection
{
$permissions = $user->allPermissions();
return $this->collection($permissions, $this->getPermissionTransformer());
}
public function includeIntegrations(User $user): Item
{
return $this->item($user, $this->getIntegrationsTransformer());
}
private function getTeamTransformer(): TransformerAbstract
{
return $this->container->get(TeamTransformer::class);
}
private function getGroupTransformer(): GroupTransformer
{
return $this->container->get(GroupTransformer::class);
}
private function getIntegrationsTransformer(): IntegrationTransformer
{
return $this->container->get(IntegrationTransformer::class);
}
private function getPermissionTransformer(): PermissionTransformer
{
return $this->container->get(PermissionTransformer::class);
}
private function getRoleTransformer(): RoleTransformer
{
return $this->container->get(RoleTransformer::class);
}
private function getJobTitleTransformer(): JobTitleTransformer
{
return $this->container->get(JobTitleTransformer::class);
}
private function getSidekickService(): SidekickService
{
/** @var SidekickService */
return $this->container->get(SidekickService::class);
}
private function getUserService(): UserService
{
/** @var UserService */
return $this->container->get(UserService::class);
}
private function getAutomatedReportsRepository(): AutomatedReportsRepository
{
/** @var AutomatedReportsRepository */
return $this->container->get(AutomatedReportsRepository::class);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
36
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\DealInsights;
use Doctrine\DBAL\Connection;
use Generator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Jiminny\Component\DealInsights\Forecast\DealData;
use Jiminny\Component\DealInsights\Forecast\DealsFilter;
use Jiminny\Component\DealInsights\QueryBuilder\QueryBuilder;
use Jiminny\Component\DealInsights\QueryBuilder\Visitor\QueryBuilderVisitorInterface;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Stage;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Models;
use Jiminny\Services\Crm\IntegrationApp\DTO\Utils\UrlGeneratorInterface;
use Jiminny\Services\Crm\ProviderRegistry;
use Jiminny\Traits\RequiresUUID;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Eloquent;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class DealsRepository implements DealsRepositoryInterface
{
private Connection $connection;
private ProviderRegistry $providerRegistry;
/**
* @var QueryBuilderVisitorInterface[]
*/
private array $visitors = [];
/**
* @param QueryBuilderVisitorInterface[] $visitors
*/
public function __construct(Connection $connection, ProviderRegistry $crmProviderRegistry, array $visitors = [])
{
$this->connection = $connection;
$this->providerRegistry = $crmProviderRegistry;
foreach ($visitors as $visitor) {
$this->visitors[$visitor->getIdentifier()] = $visitor;
}
}
public function getDeals(CriteriaInterface $criteria): array
{
$context = $criteria->getContext();
$team = $context->getTeam();
$crmService = $this->getCrmService($team);
$qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);
$qb = $this->getSearchSelectAndWhereClauses($qb);
$this->visit($qb, $criteria);
return $this->execute($team, $crmService, $qb);
}
public function getDeal(Team $team, int $id): array
{
$crmService = $this->getCrmService($team);
$qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);
$qb = $this->getSearchSelectAndWhereClauses($qb);
$qb->andWhere('opp.id = :id')->setParameter('id', $id);
return $this->execute($team, $crmService, $qb);
}
public function getCrmFieldData(array $crmFields, int $crmId, array $opportunityIds = [])
{
$qb = new QueryBuilder($this->connection);
$qb
->select('f.id', 'f.crm_provider_id AS field_name', 'f.label', 'fd.object_id AS dealId', 'fd.value')
->from('crm_fields', 'f')
->join('f', 'crm_field_data', 'fd', 'fd.crm_field_id = f.id')
->where('f.crm_configuration_id = :crm')
->andWhere('f.object_type = :type')
->andWhere('fd.object_id IN (' . implode(',', $opportunityIds) . ')')
->orderBy('fd.object_id', 'ASC')
->addOrderBy('fd.updated_at', 'ASC')
->setParameter('type', Field::OBJECT_OPPORTUNITY)
->setParameter('crm', $crmId)
;
if (! empty($crmFields)) {
$fields = array_map(fn ($value): string => '"' . $value . '"', $crmFields);
$qb->andWhere('f.crm_provider_id IN (' . implode(',', $fields) . ')');
}
return $qb->executeQuery()->fetchAllAssociative();
}
public function getTotalsInDefaultCurrency(CriteriaInterface $criteria): array
{
$qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);
$qb
->select('SUM(opp.value) as total')
->addSelect('count(*) as `count`')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'))
;
$this->visit($qb, $criteria);
return $qb->executeQuery()->fetchAssociative();
}
public function getTotals(CriteriaInterface $criteria, string $defaultCurrency): array
{
$qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);
$qb
->select('COALESCE(opp.currency_code, "' . $defaultCurrency . '") AS currency')
->addSelect('SUM(opp.value) as total')
->addSelect('count(*) as `count`')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'))
->groupBy('currency')
;
$this->visit($qb, $criteria);
return $qb->executeQuery()->fetchAllAssociative();
}
public function getDealActivities(CriteriaInterface $criteria): array
{
$qb = Activity::with(['participants', 'user'])
->where('opportunity_id', $criteria->getOpportunityId())
->whereDate('actual_start_time', '>=', $criteria->getPeriod()->getStartDate())
->whereDate('actual_start_time', '<=', $criteria->getPeriod()->getEndDate())
->orderBy($criteria->getSortBy(), $criteria->getSortDirection())
;
// Should we filter activities by criteria? It's intended to filter deals.
return $qb->get()->all();
}
public function getStages(CriteriaInterface $criteria): array
{
$qb = new QueryBuilder($this->connection);
$qb
->select('id', 'label', 'sequence')
->from('stages', 's')
->where('crm_configuration_id = :crm_configuration_id')
->andWhere('type = :type')
->orderBy('sequence', 'ASC')
->setParameter('crm_configuration_id', $criteria->getContext()->getTeam()->getCrmConfiguration()->getId())
->setParameter('type', Stage::TYPE_OPPORTUNITY);
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$result[$row['id']] = [
'label' => $row['label'],
'sequence' => $row['sequence'],
];
}
return $result;
}
public function getConfigurationStages(Configuration $configuration): Collection
{
return $configuration
->stages()
->where('type', Stage::TYPE_OPPORTUNITY)
->get();
}
public function getPipelineData(Configuration $crm): array
{
$qb = new QueryBuilder($this->connection);
$provider = $crm->provider;
$qb
->select('s.label', 's.crm_provider_id', 's.sequence', 'bps.business_process_id AS pipeline_id')
->from('stages', 's')
->join('s', 'business_process_stages', 'bps', 's.id=bps.stage_id')
->where('s.crm_configuration_id = :crm_configuration_id')
->andWhere('s.type = :type')
->orderBy('bps.business_process_id', 'ASC')
->addOrderBy('s.sequence', 'ASC')
->setParameter('crm_configuration_id', $crm->id)
->setParameter('type', Stage::TYPE_OPPORTUNITY)
;
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$value = $provider === Configuration::PROVIDER_SALESFORCE ? $row['label'] : $row['crm_provider_id'];
$result[$row['pipeline_id']][] = [
'value' => $value,
'label' => $row['label'],
'sequence' => $row['sequence'],
];
}
return $result;
}
private function createQueryBuilder(string $realm): QueryBuilder
{
return (new QueryBuilder($this->connection))
->setRealm($realm)
->from('opportunities', 'opp')
->leftJoin('opp', 'record_types', 'rt', 'opp.record_type_id = rt.id')
->leftJoin('opp', 'users', 'usr', 'opp.user_id = usr.id')
->leftJoin('opp', 'accounts', 'acc', 'opp.account_id = acc.id')
;
}
/**
* Applies all applicable visitors and returns the IDs of the executed ones
*
* @return string[]
*/
private function visit(QueryBuilder $queryBuilder, CriteriaInterface $criteria): array
{
$queryVisitors = [];
foreach ($this->visitors as $visitor) {
if ($visitor->isSatisfiedBy($criteria, $queryBuilder->getRealm())) {
$visitor->visit($queryBuilder, $criteria);
$queryVisitors[] = $visitor->getIdentifier();
}
}
return $queryVisitors;
}
private function hydrateStages(array $deals): array
{
foreach ($this->fetchStages(array_keys($deals)) as $stage) {
$oppId = (int) $stage['opportunity_id'];
if (! isset($deals[$oppId])) {
continue; // or throw??!
}
$deals[$oppId]['stages'][] = [
'id' => $stage['stage_id'],
'name' => $stage['label'],
'enteredAt' => $stage['created_at'],
];
}
return $deals;
}
/**
* @param int[] $dealIds
*/
private function fetchStages(array $dealIds): array
{
if (empty($dealIds)) {
return [];
}
$qb = new QueryBuilder($this->connection);
$qb
->select('os.opportunity_id', 's.id AS stage_id', 's.label', 's.created_at')
->from('opportunity_stages', 'os')
->leftJoin('os', 'stages', 's', 'os.stage_id=s.id')
->where($qb->expr()->in('os.opportunity_id', $dealIds))
->orderBy('os.opportunity_id', 'ASC')
->addOrderBy('s.created_at', 'ASC')
;
return $qb->executeQuery()->fetchAllAssociative();
}
private function execute(Team $team, ServiceInterface $crmService, QueryBuilder $qb): array
{
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$data = [
'uuid' => RequiresUUID::toNormal($row['uuid']),
'name' => $row['name'],
'url' => $crmService->generateProviderUrl($row['opp_provider_id'], 'opportunity'),
'account' => [
'name' => $row['acc_name'],
'url' => $crmService->generateProviderUrl(
providerId: $row['acc_provider_id'],
objectType: $row['acc_is_internal'] ? 'internal-account' : 'account'
),
],
'owner' => null,
'rawValue' => [
'amount' => (float) $row['value'],
'currency' => $row['currency_code'],
],
'value' => formatOpportunityValue((float) $row['value'], $row['currency_code']),
'openDate' => $row['remotely_created_at'] ?? null,
'closeDate' => $row['close_date'] ?? null,
'stages' => [],
'currentPipelineId' => $row['pipeline_id'],
'currentStage' => [
'id' => $row['stage_id'],
'enteredAt' => $row['stage_updated_at'],
],
'currentStageUpdatedAt' => $row['stage_updated_at'],
'isClosed' => (bool) $row['is_closed'],
'isWon' => (bool) $row['is_won'],
];
if (isset($row['owner_uuid'])) {
$data['owner'] = [
'uuid' => RequiresUUID::toNormal($row['owner_uuid']),
'name' => $row['owner_name'],
'photoUrl' => $row['owner_photo'] === null
? null
: client_cdn($row['owner_photo'], $team),
'id' => $row['owner_id'],
'job' => $row['owner_job'],
];
}
$result[(int) $row['opp_id']] = $data;
}
return $this->hydrateStages($result);
}
private function getSearchSelectAndWhereClauses(QueryBuilder $queryBuilder): QueryBuilder
{
$qb = clone $queryBuilder;
$qb->leftJoin('usr', 'job_titles', 'jt', 'usr.job_title_id = jt.id');
$qb
->select(...[
'opp.id as opp_id',
'opp.uuid',
'opp.name',
'opp.value',
'opp.currency_code',
'opp.close_date',
'opp.remotely_created_at',
'opp.is_closed',
'opp.is_won',
])
->addSelect(...[
'usr.uuid as owner_uuid',
'usr.name AS owner_name',
'usr.photo_path as owner_photo',
'usr.id AS owner_id',
'jt.name as owner_job',
])
->addSelect('opp.stage_id', 'opp.stage_updated_at')
->addSelect(...[
'acc.name AS acc_name',
'acc.is_internal as acc_is_internal',
'opp.stage_updated_at',
'acc.crm_provider_id AS acc_provider_id',
'opp.crm_provider_id AS opp_provider_id',
])
->addSelect('rt.business_process_id AS pipeline_id')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not display deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'));
return $qb;
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws SocialAccountTokenInvalidException
*/
private function getCrmService(Team $team): ServiceInterface
{
$crmService = $this->providerRegistry->get($team->crm->provider);
$crmService->setConfiguration($team->crm);
if ($crmService instanceof UrlGeneratorInterface) {
$crmService->setCrmUrlGenerator($team->crm);
}
return $crmService;
}
/**
*
* @return Generator<DealData>
*/
public function getForecastData(DealsFilter $filter): Generator
{
$opportunities = DB::query()
->select([
'o.value',
'o.close_date',
'o.currency_code',
'o.is_won',
'o.is_closed',
'o.probability',
'o.forecast_category',
])
->from('opportunities', 'o')
->join('users', 'users.id', '=', 'o.user_id')
->join('groups', 'groups.id', '=', 'users.group_id')
->where('users.team_id', $filter->getTeam()->getId())
->where('o.close_date', '>=', $filter->getStartDate())
->where('o.close_date', '<=', $filter->getEndDate())
->where('o.currency_code', $filter->getCurrency())
->where('o.deleted_at', '=', null)
;
$userUuidList = $filter->getUserUuidList();
if (! empty($userUuidList)) {
$userUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $userUuidList);
$opportunities->whereIn('users.uuid', $userUuidList);
}
$groupUuidList = $filter->getGroupUuidList();
if (! empty($groupUuidList)) {
$groupUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $groupUuidList);
$opportunities->whereIn('groups.uuid', $groupUuidList);
}
foreach ($opportunities->cursor() as $row) {
yield new DealData(
(float) $row->value,
$row->close_date,
! empty($row->is_won),
! empty($row->is_closed),
$row->probability ?: 0,
$row->forecast_category ?: '',
);
}
}
public function getUserOpportunitySubscriptions(User $user, array $opportunityIds): Collection
{
return $user->subscriptionSets()
->where(static function (Eloquent\Builder $query): void {
$query
->whereNull('expired_at')
->orWhere('expired_at', '>=', now());
})
->join('activity_subscriptions', function (Builder $join) use ($opportunityIds) {
$join
->on('subscription_set_id', '=', 'activity_subscription_sets.id');
$join
->where('followable_type', Models\Activity\Subscription::FOLLOWABLE_TYPE_OPPORTUNITY)
->whereIn('followable_id', $opportunityIds);
})
->pluck('followable_id');
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
Activity
ActivityAggregator.php, class
ActivityAggregatorInterface.php, interface
DatabaseActivities.php, class
DatasourceInterface.php, interface
RelatedActivity.php, class
RelatedActivityInterface.php, interface
Commands
Comments
Forecast
Jobs
QueryBuilder
Services
ClosingPeriodOptionDecorator.php, class
CreatedPeriodOptionDecorator.php, class
Criteria.php, class
CriteriaInterface.php, interface
CriteriaNormalizer.php, class
CrmService.php, class
CrmServiceInterface.php, interface...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.10139628,"height":0.025538707},"help_text":"Git Branch: JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.7972075,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"RequestGenerateAskJiminnyReportJobTest","depth":6,"bounds":{"left":0.8125,"top":0.019952115,"width":0.10305851,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"12","depth":4,"bounds":{"left":0.66921544,"top":0.15003991,"width":0.009640957,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.68085104,"top":0.15003991,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.69049203,"top":0.14844373,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.6978058,"top":0.14844373,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Http\\Transformers;\n\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\Sidekick\\SidekickService;\nuse Jiminny\\Exceptions\\ActivityProviderException;\nuse Jiminny\\Http\\Controllers\\Settings\\Users\\Utils\\UserSetting;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\JobTitle;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Notification\\Messengers\\MsTeams;\nuse Jiminny\\Services\\UserService;\nuse League\\Fractal\\Resource;\nuse League\\Fractal\\Resource\\Item;\nuse League\\Fractal\\TransformerAbstract;\n\nclass UserTransformer extends TransformerAbstract\n{\n protected array $availableIncludes = [\n 'team',\n 'group',\n 'job',\n 'roles',\n 'permissions',\n ];\n\n private Container $container;\n\n private bool $withSelfVisibility = false;\n\n public function __construct(?Container $container = null)\n {\n $this->container = $container ?? app();\n }\n\n public function withSelfVisibility(): self\n {\n $this->withSelfVisibility = true;\n\n return $this;\n }\n\n /**\n * @throws ActivityProviderException\n *\n * @return array<string, mixed>\n */\n public function transform(User $user): array\n {\n $attributes = [\n 'id' => $user->getUuid(),\n 'name' => $user->getName(),\n 'firstName' => $user->getFirstName(),\n 'photoUrl' => $user->getPhotoUrl(),\n 'conferenceRecordPreference' => $user->checkConferenceRecordPreference(),\n 'conferenceRecordInternalPreference' => $user->checkConferenceRecordInternalPreference(),\n // DO NOT USE User::isCrmRequired as it is not hydrated when fetched from ES!\n 'crmRequired' => $user->crm_required,\n 'slackFollowUp' => $user->slack_follow_up,\n ];\n\n // DO NOT USE User::getId as it is not hydrated when fetched from ES!\n if ($this->withSelfVisibility || (auth()->check() && auth()->user()->id === $user->id)) {\n $softphoneHasVoiceCapability = $user->hasSoftphoneNumberCapabilities()\n && $user->getSoftphoneNumberCapabilities()->hasVoiceCapability()\n ;\n\n $conferenceSidekickOpen = $user->getConferenceSidekickOpen();\n $softphoneSidekickOpen = $user->getSoftphoneSidekickOpen();\n $conferenceSidekickPopupOverridden = false;\n $softphoneSidekickPopupOverridden = false;\n $hasSidekickEnabled = true;\n\n if ($user->getTeam()->hasFeature(FeatureEnum::SIDEKICK_SETTINGS)) {\n $sidekickService = $this->getSidekickService();\n\n $sidekickData = $sidekickService->getSidekickSettingsForUser($user);\n\n $conferenceSidekickOpen = $sidekickData['conferenceSettings'];\n $softphoneSidekickOpen = $sidekickData['softphoneSettings'];\n $conferenceSidekickPopupOverridden = $sidekickData['conferenceSidekickPopupOverridden'];\n $softphoneSidekickPopupOverridden = $sidekickData['softphoneSidekickPopupOverridden'];\n $hasSidekickEnabled = $sidekickData['sidekickEnabled'];\n }\n\n $userService = $this->getUserService();\n $dealInsightsPeriod = $userService->getDealInsightTimelinePeriod($user);\n $dataFormatCountryCode = $userService->getDateTimeCountryCode($user);\n\n // Attributes for the user only.\n $attributes += [\n 'conferenceJoinReminder' => $user->conference_join_reminder,\n 'softphoneInboundRecordPreference' => $user->checkSoftphoneInboundRecordPreference(),\n 'softphoneOutboundRecordPreference' => $user->checkSoftphoneOutboundRecordPreference(),\n 'softphoneInboundDestination' => $user->softphone_inbound_destination,\n 'softphoneHasVoiceCapability' => $softphoneHasVoiceCapability,\n 'softphoneNumber' => $user->getSoftPhoneNumber(),\n 'formattedSoftphoneNumber' => $user->getFormattedSoftphoneNumberAttribute(),\n 'email' => $user->getEmailAddress(),\n 'secondaryEmail' => $user->getSecondaryEmailAddress(),\n 'phone' => $user->phone,\n 'secondaryPhone' => $user->secondary_phone,\n 'callerId' => $user->getCallerId(),\n 'countryCode' => $user->getCountryCode(),\n 'timezone' => $user->getTimezone()->getName(),\n 'language' => $user->getLanguage(),\n 'locales' => $this->container->get(UserRepository::class)->getUserLocales($user),\n 'status' => $user->getStatus(),\n 'hash' => $user->generateHash(),\n 'registrationDate' => $user->created_at ? $user->created_at->toIso8601String() : null,\n 'notifyLiveCoaching' => $user->notify_live_coaching,\n 'activityLogReminder' => $user->activity_log_reminder,\n 'conferenceSidekickOpen' => $conferenceSidekickOpen,\n 'softphoneSidekickOpen' => $softphoneSidekickOpen,\n 'conferenceSidekickPopupOverridden' => $conferenceSidekickPopupOverridden,\n 'softphoneSidekickPopupOverridden' => $softphoneSidekickPopupOverridden,\n 'hasSidekickEnabled' => $hasSidekickEnabled,\n 'activityActionItems' => $user->activity_action_items,\n 'syncEmail' => $user->isSyncEmailEnabled(),\n 'syncConference' => $user->sync_conference,\n 'syncDialer' => $user->shouldSyncDialer(),\n 'needsToConfigurePhoneNumber' => $this->container\n ->get('onboarding_phone_decider')\n ->isOnboardable($user),\n 'shouldShowPhoneNumberField' => $this->container\n ->get('onboarding_phone_decider')\n ->shouldShowPhoneNumberField($user),\n UserSetting::DEAL_INSIGHTS_TIMELINE_PERIOD => $dealInsightsPeriod,\n 'countryByTimezone' => $dataFormatCountryCode,\n 'conferenceSlug' => $user->getConferenceSlug(),\n 'conferenceRecordExternalOrganizerPreference' =>\n $userService->isConferenceRecordExternalOrganizerPreferenceEnabled($user),\n 'hasGeneratedAiReports' => $this->getAutomatedReportsRepository()->countUserReports($user) > 0,\n 'sendEmailWhenExportLinkIsOpened' => $userService->canSendEmailWhenExportLinkIsOpened($user),\n ];\n\n if ($user->softphone_debug) {\n $attributes += [\n 'debugSoftphone' => $user->softphone_debug, // Needed?\n ];\n }\n }\n\n if ($user->getTeam()->getNotificationProvider() === Team::NOTIFICATION_PROVIDER_MSTEAMS) {\n $socialAccountMS = $user->getSocialAccount(Team::CALENDAR_PROVIDER_OFFICE);\n $state = $socialAccountMS !== null\n ? str_contains($socialAccountMS->auth_scope, MsTeams::SCOPE_CHAT_CREATE)\n : null;\n\n $attributes['integrations']['office'] = [\n 'displayName' => 'Microsoft Teams',\n 'apiName' => 'microsoft-teams',\n 'types' => ['notification'],\n 'state' => $state ? Provider::STATE_INSTALLED : Provider::STATE_NOT_INSTALLED,\n 'logo' => cdn('img/ms-teams-logo.svg'),\n 'installationStrategy' => 'oauth',\n ];\n }\n\n return $attributes;\n }\n\n public function includeTeam(User $user): Item\n {\n $team = $user->getTeam();\n\n return $this->item($team, $this->getTeamTransformer());\n }\n\n public function includeGroup(User $user): ?Item\n {\n $group = $user->getGroup();\n if ($group === null) {\n return null;\n }\n\n return $this->item($group, $this->getGroupTransformer());\n }\n\n public function includeJob(User $user): ?Item\n {\n $job = $user->getJobTitle();\n\n if (! $job instanceof JobTitle) {\n return null;\n }\n\n return $this->item($job, $this->getJobTitleTransformer());\n }\n\n public function includeRoles(User $user): Resource\\Collection\n {\n /** @var Collection<int, string> $roles */\n $roles = $user->roles()\n ->where('is_visible', true)\n ->pluck('name')\n ->toArray();\n\n return $this->collection($roles, $this->getRoleTransformer());\n }\n\n public function includePermissions(User $user): Resource\\Collection\n {\n $permissions = $user->allPermissions();\n\n return $this->collection($permissions, $this->getPermissionTransformer());\n }\n\n public function includeIntegrations(User $user): Item\n {\n return $this->item($user, $this->getIntegrationsTransformer());\n }\n\n private function getTeamTransformer(): TransformerAbstract\n {\n return $this->container->get(TeamTransformer::class);\n }\n\n private function getGroupTransformer(): GroupTransformer\n {\n return $this->container->get(GroupTransformer::class);\n }\n\n private function getIntegrationsTransformer(): IntegrationTransformer\n {\n return $this->container->get(IntegrationTransformer::class);\n }\n\n private function getPermissionTransformer(): PermissionTransformer\n {\n return $this->container->get(PermissionTransformer::class);\n }\n\n private function getRoleTransformer(): RoleTransformer\n {\n return $this->container->get(RoleTransformer::class);\n }\n\n private function getJobTitleTransformer(): JobTitleTransformer\n {\n return $this->container->get(JobTitleTransformer::class);\n }\n\n private function getSidekickService(): SidekickService\n {\n /** @var SidekickService */\n return $this->container->get(SidekickService::class);\n }\n\n private function getUserService(): UserService\n {\n /** @var UserService */\n return $this->container->get(UserService::class);\n }\n\n private function getAutomatedReportsRepository(): AutomatedReportsRepository\n {\n /** @var AutomatedReportsRepository */\n return $this->container->get(AutomatedReportsRepository::class);\n }\n}","depth":4,"value":"<?php\n\nnamespace Jiminny\\Http\\Transformers;\n\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\Sidekick\\SidekickService;\nuse Jiminny\\Exceptions\\ActivityProviderException;\nuse Jiminny\\Http\\Controllers\\Settings\\Users\\Utils\\UserSetting;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\JobTitle;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Notification\\Messengers\\MsTeams;\nuse Jiminny\\Services\\UserService;\nuse League\\Fractal\\Resource;\nuse League\\Fractal\\Resource\\Item;\nuse League\\Fractal\\TransformerAbstract;\n\nclass UserTransformer extends TransformerAbstract\n{\n protected array $availableIncludes = [\n 'team',\n 'group',\n 'job',\n 'roles',\n 'permissions',\n ];\n\n private Container $container;\n\n private bool $withSelfVisibility = false;\n\n public function __construct(?Container $container = null)\n {\n $this->container = $container ?? app();\n }\n\n public function withSelfVisibility(): self\n {\n $this->withSelfVisibility = true;\n\n return $this;\n }\n\n /**\n * @throws ActivityProviderException\n *\n * @return array<string, mixed>\n */\n public function transform(User $user): array\n {\n $attributes = [\n 'id' => $user->getUuid(),\n 'name' => $user->getName(),\n 'firstName' => $user->getFirstName(),\n 'photoUrl' => $user->getPhotoUrl(),\n 'conferenceRecordPreference' => $user->checkConferenceRecordPreference(),\n 'conferenceRecordInternalPreference' => $user->checkConferenceRecordInternalPreference(),\n // DO NOT USE User::isCrmRequired as it is not hydrated when fetched from ES!\n 'crmRequired' => $user->crm_required,\n 'slackFollowUp' => $user->slack_follow_up,\n ];\n\n // DO NOT USE User::getId as it is not hydrated when fetched from ES!\n if ($this->withSelfVisibility || (auth()->check() && auth()->user()->id === $user->id)) {\n $softphoneHasVoiceCapability = $user->hasSoftphoneNumberCapabilities()\n && $user->getSoftphoneNumberCapabilities()->hasVoiceCapability()\n ;\n\n $conferenceSidekickOpen = $user->getConferenceSidekickOpen();\n $softphoneSidekickOpen = $user->getSoftphoneSidekickOpen();\n $conferenceSidekickPopupOverridden = false;\n $softphoneSidekickPopupOverridden = false;\n $hasSidekickEnabled = true;\n\n if ($user->getTeam()->hasFeature(FeatureEnum::SIDEKICK_SETTINGS)) {\n $sidekickService = $this->getSidekickService();\n\n $sidekickData = $sidekickService->getSidekickSettingsForUser($user);\n\n $conferenceSidekickOpen = $sidekickData['conferenceSettings'];\n $softphoneSidekickOpen = $sidekickData['softphoneSettings'];\n $conferenceSidekickPopupOverridden = $sidekickData['conferenceSidekickPopupOverridden'];\n $softphoneSidekickPopupOverridden = $sidekickData['softphoneSidekickPopupOverridden'];\n $hasSidekickEnabled = $sidekickData['sidekickEnabled'];\n }\n\n $userService = $this->getUserService();\n $dealInsightsPeriod = $userService->getDealInsightTimelinePeriod($user);\n $dataFormatCountryCode = $userService->getDateTimeCountryCode($user);\n\n // Attributes for the user only.\n $attributes += [\n 'conferenceJoinReminder' => $user->conference_join_reminder,\n 'softphoneInboundRecordPreference' => $user->checkSoftphoneInboundRecordPreference(),\n 'softphoneOutboundRecordPreference' => $user->checkSoftphoneOutboundRecordPreference(),\n 'softphoneInboundDestination' => $user->softphone_inbound_destination,\n 'softphoneHasVoiceCapability' => $softphoneHasVoiceCapability,\n 'softphoneNumber' => $user->getSoftPhoneNumber(),\n 'formattedSoftphoneNumber' => $user->getFormattedSoftphoneNumberAttribute(),\n 'email' => $user->getEmailAddress(),\n 'secondaryEmail' => $user->getSecondaryEmailAddress(),\n 'phone' => $user->phone,\n 'secondaryPhone' => $user->secondary_phone,\n 'callerId' => $user->getCallerId(),\n 'countryCode' => $user->getCountryCode(),\n 'timezone' => $user->getTimezone()->getName(),\n 'language' => $user->getLanguage(),\n 'locales' => $this->container->get(UserRepository::class)->getUserLocales($user),\n 'status' => $user->getStatus(),\n 'hash' => $user->generateHash(),\n 'registrationDate' => $user->created_at ? $user->created_at->toIso8601String() : null,\n 'notifyLiveCoaching' => $user->notify_live_coaching,\n 'activityLogReminder' => $user->activity_log_reminder,\n 'conferenceSidekickOpen' => $conferenceSidekickOpen,\n 'softphoneSidekickOpen' => $softphoneSidekickOpen,\n 'conferenceSidekickPopupOverridden' => $conferenceSidekickPopupOverridden,\n 'softphoneSidekickPopupOverridden' => $softphoneSidekickPopupOverridden,\n 'hasSidekickEnabled' => $hasSidekickEnabled,\n 'activityActionItems' => $user->activity_action_items,\n 'syncEmail' => $user->isSyncEmailEnabled(),\n 'syncConference' => $user->sync_conference,\n 'syncDialer' => $user->shouldSyncDialer(),\n 'needsToConfigurePhoneNumber' => $this->container\n ->get('onboarding_phone_decider')\n ->isOnboardable($user),\n 'shouldShowPhoneNumberField' => $this->container\n ->get('onboarding_phone_decider')\n ->shouldShowPhoneNumberField($user),\n UserSetting::DEAL_INSIGHTS_TIMELINE_PERIOD => $dealInsightsPeriod,\n 'countryByTimezone' => $dataFormatCountryCode,\n 'conferenceSlug' => $user->getConferenceSlug(),\n 'conferenceRecordExternalOrganizerPreference' =>\n $userService->isConferenceRecordExternalOrganizerPreferenceEnabled($user),\n 'hasGeneratedAiReports' => $this->getAutomatedReportsRepository()->countUserReports($user) > 0,\n 'sendEmailWhenExportLinkIsOpened' => $userService->canSendEmailWhenExportLinkIsOpened($user),\n ];\n\n if ($user->softphone_debug) {\n $attributes += [\n 'debugSoftphone' => $user->softphone_debug, // Needed?\n ];\n }\n }\n\n if ($user->getTeam()->getNotificationProvider() === Team::NOTIFICATION_PROVIDER_MSTEAMS) {\n $socialAccountMS = $user->getSocialAccount(Team::CALENDAR_PROVIDER_OFFICE);\n $state = $socialAccountMS !== null\n ? str_contains($socialAccountMS->auth_scope, MsTeams::SCOPE_CHAT_CREATE)\n : null;\n\n $attributes['integrations']['office'] = [\n 'displayName' => 'Microsoft Teams',\n 'apiName' => 'microsoft-teams',\n 'types' => ['notification'],\n 'state' => $state ? Provider::STATE_INSTALLED : Provider::STATE_NOT_INSTALLED,\n 'logo' => cdn('img/ms-teams-logo.svg'),\n 'installationStrategy' => 'oauth',\n ];\n }\n\n return $attributes;\n }\n\n public function includeTeam(User $user): Item\n {\n $team = $user->getTeam();\n\n return $this->item($team, $this->getTeamTransformer());\n }\n\n public function includeGroup(User $user): ?Item\n {\n $group = $user->getGroup();\n if ($group === null) {\n return null;\n }\n\n return $this->item($group, $this->getGroupTransformer());\n }\n\n public function includeJob(User $user): ?Item\n {\n $job = $user->getJobTitle();\n\n if (! $job instanceof JobTitle) {\n return null;\n }\n\n return $this->item($job, $this->getJobTitleTransformer());\n }\n\n public function includeRoles(User $user): Resource\\Collection\n {\n /** @var Collection<int, string> $roles */\n $roles = $user->roles()\n ->where('is_visible', true)\n ->pluck('name')\n ->toArray();\n\n return $this->collection($roles, $this->getRoleTransformer());\n }\n\n public function includePermissions(User $user): Resource\\Collection\n {\n $permissions = $user->allPermissions();\n\n return $this->collection($permissions, $this->getPermissionTransformer());\n }\n\n public function includeIntegrations(User $user): Item\n {\n return $this->item($user, $this->getIntegrationsTransformer());\n }\n\n private function getTeamTransformer(): TransformerAbstract\n {\n return $this->container->get(TeamTransformer::class);\n }\n\n private function getGroupTransformer(): GroupTransformer\n {\n return $this->container->get(GroupTransformer::class);\n }\n\n private function getIntegrationsTransformer(): IntegrationTransformer\n {\n return $this->container->get(IntegrationTransformer::class);\n }\n\n private function getPermissionTransformer(): PermissionTransformer\n {\n return $this->container->get(PermissionTransformer::class);\n }\n\n private function getRoleTransformer(): RoleTransformer\n {\n return $this->container->get(RoleTransformer::class);\n }\n\n private function getJobTitleTransformer(): JobTitleTransformer\n {\n return $this->container->get(JobTitleTransformer::class);\n }\n\n private function getSidekickService(): SidekickService\n {\n /** @var SidekickService */\n return $this->container->get(SidekickService::class);\n }\n\n private function getUserService(): UserService\n {\n /** @var UserService */\n return $this->container->get(UserService::class);\n }\n\n private function getAutomatedReportsRepository(): AutomatedReportsRepository\n {\n /** @var AutomatedReportsRepository */\n return $this->container->get(AutomatedReportsRepository::class);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"36","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\DealInsights;\n\nuse Doctrine\\DBAL\\Connection;\nuse Generator;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Facades\\DB;\nuse Jiminny\\Component\\DealInsights\\Forecast\\DealData;\nuse Jiminny\\Component\\DealInsights\\Forecast\\DealsFilter;\nuse Jiminny\\Component\\DealInsights\\QueryBuilder\\QueryBuilder;\nuse Jiminny\\Component\\DealInsights\\QueryBuilder\\Visitor\\QueryBuilderVisitorInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Models;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\Utils\\UrlGeneratorInterface;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Database\\Eloquent;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\n\nclass DealsRepository implements DealsRepositoryInterface\n{\n private Connection $connection;\n\n private ProviderRegistry $providerRegistry;\n\n /**\n * @var QueryBuilderVisitorInterface[]\n */\n private array $visitors = [];\n\n /**\n * @param QueryBuilderVisitorInterface[] $visitors\n */\n public function __construct(Connection $connection, ProviderRegistry $crmProviderRegistry, array $visitors = [])\n {\n $this->connection = $connection;\n $this->providerRegistry = $crmProviderRegistry;\n\n foreach ($visitors as $visitor) {\n $this->visitors[$visitor->getIdentifier()] = $visitor;\n }\n }\n\n public function getDeals(CriteriaInterface $criteria): array\n {\n $context = $criteria->getContext();\n $team = $context->getTeam();\n $crmService = $this->getCrmService($team);\n\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);\n $qb = $this->getSearchSelectAndWhereClauses($qb);\n\n $this->visit($qb, $criteria);\n\n return $this->execute($team, $crmService, $qb);\n }\n\n public function getDeal(Team $team, int $id): array\n {\n $crmService = $this->getCrmService($team);\n\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);\n $qb = $this->getSearchSelectAndWhereClauses($qb);\n $qb->andWhere('opp.id = :id')->setParameter('id', $id);\n\n return $this->execute($team, $crmService, $qb);\n }\n\n public function getCrmFieldData(array $crmFields, int $crmId, array $opportunityIds = [])\n {\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('f.id', 'f.crm_provider_id AS field_name', 'f.label', 'fd.object_id AS dealId', 'fd.value')\n ->from('crm_fields', 'f')\n ->join('f', 'crm_field_data', 'fd', 'fd.crm_field_id = f.id')\n ->where('f.crm_configuration_id = :crm')\n ->andWhere('f.object_type = :type')\n ->andWhere('fd.object_id IN (' . implode(',', $opportunityIds) . ')')\n ->orderBy('fd.object_id', 'ASC')\n ->addOrderBy('fd.updated_at', 'ASC')\n\n ->setParameter('type', Field::OBJECT_OPPORTUNITY)\n ->setParameter('crm', $crmId)\n ;\n\n if (! empty($crmFields)) {\n $fields = array_map(fn ($value): string => '\"' . $value . '\"', $crmFields);\n $qb->andWhere('f.crm_provider_id IN (' . implode(',', $fields) . ')');\n }\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n public function getTotalsInDefaultCurrency(CriteriaInterface $criteria): array\n {\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);\n\n $qb\n ->select('SUM(opp.value) as total')\n ->addSelect('count(*) as `count`')\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'))\n ;\n\n $this->visit($qb, $criteria);\n\n return $qb->executeQuery()->fetchAssociative();\n }\n\n public function getTotals(CriteriaInterface $criteria, string $defaultCurrency): array\n {\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);\n\n $qb\n ->select('COALESCE(opp.currency_code, \"' . $defaultCurrency . '\") AS currency')\n ->addSelect('SUM(opp.value) as total')\n ->addSelect('count(*) as `count`')\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'))\n ->groupBy('currency')\n ;\n\n $this->visit($qb, $criteria);\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n public function getDealActivities(CriteriaInterface $criteria): array\n {\n $qb = Activity::with(['participants', 'user'])\n ->where('opportunity_id', $criteria->getOpportunityId())\n ->whereDate('actual_start_time', '>=', $criteria->getPeriod()->getStartDate())\n ->whereDate('actual_start_time', '<=', $criteria->getPeriod()->getEndDate())\n ->orderBy($criteria->getSortBy(), $criteria->getSortDirection())\n ;\n\n // Should we filter activities by criteria? It's intended to filter deals.\n\n return $qb->get()->all();\n }\n\n public function getStages(CriteriaInterface $criteria): array\n {\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('id', 'label', 'sequence')\n ->from('stages', 's')\n ->where('crm_configuration_id = :crm_configuration_id')\n ->andWhere('type = :type')\n ->orderBy('sequence', 'ASC')\n\n ->setParameter('crm_configuration_id', $criteria->getContext()->getTeam()->getCrmConfiguration()->getId())\n ->setParameter('type', Stage::TYPE_OPPORTUNITY);\n\n $result = [];\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $result[$row['id']] = [\n 'label' => $row['label'],\n 'sequence' => $row['sequence'],\n ];\n }\n\n return $result;\n }\n\n public function getConfigurationStages(Configuration $configuration): Collection\n {\n return $configuration\n ->stages()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get();\n }\n\n public function getPipelineData(Configuration $crm): array\n {\n $qb = new QueryBuilder($this->connection);\n $provider = $crm->provider;\n\n $qb\n ->select('s.label', 's.crm_provider_id', 's.sequence', 'bps.business_process_id AS pipeline_id')\n ->from('stages', 's')\n ->join('s', 'business_process_stages', 'bps', 's.id=bps.stage_id')\n ->where('s.crm_configuration_id = :crm_configuration_id')\n ->andWhere('s.type = :type')\n ->orderBy('bps.business_process_id', 'ASC')\n ->addOrderBy('s.sequence', 'ASC')\n\n ->setParameter('crm_configuration_id', $crm->id)\n ->setParameter('type', Stage::TYPE_OPPORTUNITY)\n ;\n\n $result = [];\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $value = $provider === Configuration::PROVIDER_SALESFORCE ? $row['label'] : $row['crm_provider_id'];\n $result[$row['pipeline_id']][] = [\n 'value' => $value,\n 'label' => $row['label'],\n 'sequence' => $row['sequence'],\n ];\n }\n\n return $result;\n }\n\n private function createQueryBuilder(string $realm): QueryBuilder\n {\n return (new QueryBuilder($this->connection))\n ->setRealm($realm)\n ->from('opportunities', 'opp')\n ->leftJoin('opp', 'record_types', 'rt', 'opp.record_type_id = rt.id')\n ->leftJoin('opp', 'users', 'usr', 'opp.user_id = usr.id')\n ->leftJoin('opp', 'accounts', 'acc', 'opp.account_id = acc.id')\n ;\n }\n\n /**\n * Applies all applicable visitors and returns the IDs of the executed ones\n *\n * @return string[]\n */\n private function visit(QueryBuilder $queryBuilder, CriteriaInterface $criteria): array\n {\n $queryVisitors = [];\n\n foreach ($this->visitors as $visitor) {\n if ($visitor->isSatisfiedBy($criteria, $queryBuilder->getRealm())) {\n $visitor->visit($queryBuilder, $criteria);\n\n $queryVisitors[] = $visitor->getIdentifier();\n }\n }\n\n return $queryVisitors;\n }\n\n private function hydrateStages(array $deals): array\n {\n foreach ($this->fetchStages(array_keys($deals)) as $stage) {\n $oppId = (int) $stage['opportunity_id'];\n\n if (! isset($deals[$oppId])) {\n continue; // or throw??!\n }\n\n $deals[$oppId]['stages'][] = [\n 'id' => $stage['stage_id'],\n 'name' => $stage['label'],\n 'enteredAt' => $stage['created_at'],\n ];\n }\n\n return $deals;\n }\n\n /**\n * @param int[] $dealIds\n */\n private function fetchStages(array $dealIds): array\n {\n if (empty($dealIds)) {\n return [];\n }\n\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('os.opportunity_id', 's.id AS stage_id', 's.label', 's.created_at')\n ->from('opportunity_stages', 'os')\n ->leftJoin('os', 'stages', 's', 'os.stage_id=s.id')\n ->where($qb->expr()->in('os.opportunity_id', $dealIds))\n ->orderBy('os.opportunity_id', 'ASC')\n ->addOrderBy('s.created_at', 'ASC')\n ;\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n private function execute(Team $team, ServiceInterface $crmService, QueryBuilder $qb): array\n {\n $result = [];\n\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $data = [\n 'uuid' => RequiresUUID::toNormal($row['uuid']),\n 'name' => $row['name'],\n 'url' => $crmService->generateProviderUrl($row['opp_provider_id'], 'opportunity'),\n 'account' => [\n 'name' => $row['acc_name'],\n 'url' => $crmService->generateProviderUrl(\n providerId: $row['acc_provider_id'],\n objectType: $row['acc_is_internal'] ? 'internal-account' : 'account'\n ),\n ],\n 'owner' => null,\n 'rawValue' => [\n 'amount' => (float) $row['value'],\n 'currency' => $row['currency_code'],\n ],\n 'value' => formatOpportunityValue((float) $row['value'], $row['currency_code']),\n 'openDate' => $row['remotely_created_at'] ?? null,\n 'closeDate' => $row['close_date'] ?? null,\n 'stages' => [],\n 'currentPipelineId' => $row['pipeline_id'],\n 'currentStage' => [\n 'id' => $row['stage_id'],\n 'enteredAt' => $row['stage_updated_at'],\n ],\n 'currentStageUpdatedAt' => $row['stage_updated_at'],\n 'isClosed' => (bool) $row['is_closed'],\n 'isWon' => (bool) $row['is_won'],\n ];\n\n if (isset($row['owner_uuid'])) {\n $data['owner'] = [\n 'uuid' => RequiresUUID::toNormal($row['owner_uuid']),\n 'name' => $row['owner_name'],\n 'photoUrl' => $row['owner_photo'] === null\n ? null\n : client_cdn($row['owner_photo'], $team),\n 'id' => $row['owner_id'],\n 'job' => $row['owner_job'],\n ];\n }\n\n $result[(int) $row['opp_id']] = $data;\n }\n\n return $this->hydrateStages($result);\n }\n\n private function getSearchSelectAndWhereClauses(QueryBuilder $queryBuilder): QueryBuilder\n {\n $qb = clone $queryBuilder;\n $qb->leftJoin('usr', 'job_titles', 'jt', 'usr.job_title_id = jt.id');\n\n $qb\n ->select(...[\n 'opp.id as opp_id',\n 'opp.uuid',\n 'opp.name',\n 'opp.value',\n 'opp.currency_code',\n 'opp.close_date',\n 'opp.remotely_created_at',\n 'opp.is_closed',\n 'opp.is_won',\n ])\n ->addSelect(...[\n 'usr.uuid as owner_uuid',\n 'usr.name AS owner_name',\n 'usr.photo_path as owner_photo',\n 'usr.id AS owner_id',\n 'jt.name as owner_job',\n ])\n ->addSelect('opp.stage_id', 'opp.stage_updated_at')\n ->addSelect(...[\n 'acc.name AS acc_name',\n 'acc.is_internal as acc_is_internal',\n 'opp.stage_updated_at',\n 'acc.crm_provider_id AS acc_provider_id',\n 'opp.crm_provider_id AS opp_provider_id',\n ])\n ->addSelect('rt.business_process_id AS pipeline_id')\n\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not display deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'));\n\n return $qb;\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws SocialAccountTokenInvalidException\n */\n private function getCrmService(Team $team): ServiceInterface\n {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n $crmService->setConfiguration($team->crm);\n if ($crmService instanceof UrlGeneratorInterface) {\n $crmService->setCrmUrlGenerator($team->crm);\n }\n\n return $crmService;\n }\n\n /**\n *\n * @return Generator<DealData>\n */\n public function getForecastData(DealsFilter $filter): Generator\n {\n $opportunities = DB::query()\n ->select([\n 'o.value',\n 'o.close_date',\n 'o.currency_code',\n 'o.is_won',\n 'o.is_closed',\n 'o.probability',\n 'o.forecast_category',\n ])\n ->from('opportunities', 'o')\n ->join('users', 'users.id', '=', 'o.user_id')\n ->join('groups', 'groups.id', '=', 'users.group_id')\n ->where('users.team_id', $filter->getTeam()->getId())\n ->where('o.close_date', '>=', $filter->getStartDate())\n ->where('o.close_date', '<=', $filter->getEndDate())\n ->where('o.currency_code', $filter->getCurrency())\n ->where('o.deleted_at', '=', null)\n ;\n\n $userUuidList = $filter->getUserUuidList();\n if (! empty($userUuidList)) {\n $userUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $userUuidList);\n\n $opportunities->whereIn('users.uuid', $userUuidList);\n }\n\n $groupUuidList = $filter->getGroupUuidList();\n if (! empty($groupUuidList)) {\n $groupUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $groupUuidList);\n\n $opportunities->whereIn('groups.uuid', $groupUuidList);\n }\n\n foreach ($opportunities->cursor() as $row) {\n yield new DealData(\n (float) $row->value,\n $row->close_date,\n ! empty($row->is_won),\n ! empty($row->is_closed),\n $row->probability ?: 0,\n $row->forecast_category ?: '',\n );\n }\n }\n\n public function getUserOpportunitySubscriptions(User $user, array $opportunityIds): Collection\n {\n return $user->subscriptionSets()\n ->where(static function (Eloquent\\Builder $query): void {\n $query\n ->whereNull('expired_at')\n ->orWhere('expired_at', '>=', now());\n })\n ->join('activity_subscriptions', function (Builder $join) use ($opportunityIds) {\n $join\n ->on('subscription_set_id', '=', 'activity_subscription_sets.id');\n $join\n ->where('followable_type', Models\\Activity\\Subscription::FOLLOWABLE_TYPE_OPPORTUNITY)\n ->whereIn('followable_id', $opportunityIds);\n })\n ->pluck('followable_id');\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\DealInsights;\n\nuse Doctrine\\DBAL\\Connection;\nuse Generator;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Facades\\DB;\nuse Jiminny\\Component\\DealInsights\\Forecast\\DealData;\nuse Jiminny\\Component\\DealInsights\\Forecast\\DealsFilter;\nuse Jiminny\\Component\\DealInsights\\QueryBuilder\\QueryBuilder;\nuse Jiminny\\Component\\DealInsights\\QueryBuilder\\Visitor\\QueryBuilderVisitorInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Models;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\Utils\\UrlGeneratorInterface;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Database\\Eloquent;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\n\nclass DealsRepository implements DealsRepositoryInterface\n{\n private Connection $connection;\n\n private ProviderRegistry $providerRegistry;\n\n /**\n * @var QueryBuilderVisitorInterface[]\n */\n private array $visitors = [];\n\n /**\n * @param QueryBuilderVisitorInterface[] $visitors\n */\n public function __construct(Connection $connection, ProviderRegistry $crmProviderRegistry, array $visitors = [])\n {\n $this->connection = $connection;\n $this->providerRegistry = $crmProviderRegistry;\n\n foreach ($visitors as $visitor) {\n $this->visitors[$visitor->getIdentifier()] = $visitor;\n }\n }\n\n public function getDeals(CriteriaInterface $criteria): array\n {\n $context = $criteria->getContext();\n $team = $context->getTeam();\n $crmService = $this->getCrmService($team);\n\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);\n $qb = $this->getSearchSelectAndWhereClauses($qb);\n\n $this->visit($qb, $criteria);\n\n return $this->execute($team, $crmService, $qb);\n }\n\n public function getDeal(Team $team, int $id): array\n {\n $crmService = $this->getCrmService($team);\n\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);\n $qb = $this->getSearchSelectAndWhereClauses($qb);\n $qb->andWhere('opp.id = :id')->setParameter('id', $id);\n\n return $this->execute($team, $crmService, $qb);\n }\n\n public function getCrmFieldData(array $crmFields, int $crmId, array $opportunityIds = [])\n {\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('f.id', 'f.crm_provider_id AS field_name', 'f.label', 'fd.object_id AS dealId', 'fd.value')\n ->from('crm_fields', 'f')\n ->join('f', 'crm_field_data', 'fd', 'fd.crm_field_id = f.id')\n ->where('f.crm_configuration_id = :crm')\n ->andWhere('f.object_type = :type')\n ->andWhere('fd.object_id IN (' . implode(',', $opportunityIds) . ')')\n ->orderBy('fd.object_id', 'ASC')\n ->addOrderBy('fd.updated_at', 'ASC')\n\n ->setParameter('type', Field::OBJECT_OPPORTUNITY)\n ->setParameter('crm', $crmId)\n ;\n\n if (! empty($crmFields)) {\n $fields = array_map(fn ($value): string => '\"' . $value . '\"', $crmFields);\n $qb->andWhere('f.crm_provider_id IN (' . implode(',', $fields) . ')');\n }\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n public function getTotalsInDefaultCurrency(CriteriaInterface $criteria): array\n {\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);\n\n $qb\n ->select('SUM(opp.value) as total')\n ->addSelect('count(*) as `count`')\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'))\n ;\n\n $this->visit($qb, $criteria);\n\n return $qb->executeQuery()->fetchAssociative();\n }\n\n public function getTotals(CriteriaInterface $criteria, string $defaultCurrency): array\n {\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);\n\n $qb\n ->select('COALESCE(opp.currency_code, \"' . $defaultCurrency . '\") AS currency')\n ->addSelect('SUM(opp.value) as total')\n ->addSelect('count(*) as `count`')\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'))\n ->groupBy('currency')\n ;\n\n $this->visit($qb, $criteria);\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n public function getDealActivities(CriteriaInterface $criteria): array\n {\n $qb = Activity::with(['participants', 'user'])\n ->where('opportunity_id', $criteria->getOpportunityId())\n ->whereDate('actual_start_time', '>=', $criteria->getPeriod()->getStartDate())\n ->whereDate('actual_start_time', '<=', $criteria->getPeriod()->getEndDate())\n ->orderBy($criteria->getSortBy(), $criteria->getSortDirection())\n ;\n\n // Should we filter activities by criteria? It's intended to filter deals.\n\n return $qb->get()->all();\n }\n\n public function getStages(CriteriaInterface $criteria): array\n {\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('id', 'label', 'sequence')\n ->from('stages', 's')\n ->where('crm_configuration_id = :crm_configuration_id')\n ->andWhere('type = :type')\n ->orderBy('sequence', 'ASC')\n\n ->setParameter('crm_configuration_id', $criteria->getContext()->getTeam()->getCrmConfiguration()->getId())\n ->setParameter('type', Stage::TYPE_OPPORTUNITY);\n\n $result = [];\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $result[$row['id']] = [\n 'label' => $row['label'],\n 'sequence' => $row['sequence'],\n ];\n }\n\n return $result;\n }\n\n public function getConfigurationStages(Configuration $configuration): Collection\n {\n return $configuration\n ->stages()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get();\n }\n\n public function getPipelineData(Configuration $crm): array\n {\n $qb = new QueryBuilder($this->connection);\n $provider = $crm->provider;\n\n $qb\n ->select('s.label', 's.crm_provider_id', 's.sequence', 'bps.business_process_id AS pipeline_id')\n ->from('stages', 's')\n ->join('s', 'business_process_stages', 'bps', 's.id=bps.stage_id')\n ->where('s.crm_configuration_id = :crm_configuration_id')\n ->andWhere('s.type = :type')\n ->orderBy('bps.business_process_id', 'ASC')\n ->addOrderBy('s.sequence', 'ASC')\n\n ->setParameter('crm_configuration_id', $crm->id)\n ->setParameter('type', Stage::TYPE_OPPORTUNITY)\n ;\n\n $result = [];\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $value = $provider === Configuration::PROVIDER_SALESFORCE ? $row['label'] : $row['crm_provider_id'];\n $result[$row['pipeline_id']][] = [\n 'value' => $value,\n 'label' => $row['label'],\n 'sequence' => $row['sequence'],\n ];\n }\n\n return $result;\n }\n\n private function createQueryBuilder(string $realm): QueryBuilder\n {\n return (new QueryBuilder($this->connection))\n ->setRealm($realm)\n ->from('opportunities', 'opp')\n ->leftJoin('opp', 'record_types', 'rt', 'opp.record_type_id = rt.id')\n ->leftJoin('opp', 'users', 'usr', 'opp.user_id = usr.id')\n ->leftJoin('opp', 'accounts', 'acc', 'opp.account_id = acc.id')\n ;\n }\n\n /**\n * Applies all applicable visitors and returns the IDs of the executed ones\n *\n * @return string[]\n */\n private function visit(QueryBuilder $queryBuilder, CriteriaInterface $criteria): array\n {\n $queryVisitors = [];\n\n foreach ($this->visitors as $visitor) {\n if ($visitor->isSatisfiedBy($criteria, $queryBuilder->getRealm())) {\n $visitor->visit($queryBuilder, $criteria);\n\n $queryVisitors[] = $visitor->getIdentifier();\n }\n }\n\n return $queryVisitors;\n }\n\n private function hydrateStages(array $deals): array\n {\n foreach ($this->fetchStages(array_keys($deals)) as $stage) {\n $oppId = (int) $stage['opportunity_id'];\n\n if (! isset($deals[$oppId])) {\n continue; // or throw??!\n }\n\n $deals[$oppId]['stages'][] = [\n 'id' => $stage['stage_id'],\n 'name' => $stage['label'],\n 'enteredAt' => $stage['created_at'],\n ];\n }\n\n return $deals;\n }\n\n /**\n * @param int[] $dealIds\n */\n private function fetchStages(array $dealIds): array\n {\n if (empty($dealIds)) {\n return [];\n }\n\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('os.opportunity_id', 's.id AS stage_id', 's.label', 's.created_at')\n ->from('opportunity_stages', 'os')\n ->leftJoin('os', 'stages', 's', 'os.stage_id=s.id')\n ->where($qb->expr()->in('os.opportunity_id', $dealIds))\n ->orderBy('os.opportunity_id', 'ASC')\n ->addOrderBy('s.created_at', 'ASC')\n ;\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n private function execute(Team $team, ServiceInterface $crmService, QueryBuilder $qb): array\n {\n $result = [];\n\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $data = [\n 'uuid' => RequiresUUID::toNormal($row['uuid']),\n 'name' => $row['name'],\n 'url' => $crmService->generateProviderUrl($row['opp_provider_id'], 'opportunity'),\n 'account' => [\n 'name' => $row['acc_name'],\n 'url' => $crmService->generateProviderUrl(\n providerId: $row['acc_provider_id'],\n objectType: $row['acc_is_internal'] ? 'internal-account' : 'account'\n ),\n ],\n 'owner' => null,\n 'rawValue' => [\n 'amount' => (float) $row['value'],\n 'currency' => $row['currency_code'],\n ],\n 'value' => formatOpportunityValue((float) $row['value'], $row['currency_code']),\n 'openDate' => $row['remotely_created_at'] ?? null,\n 'closeDate' => $row['close_date'] ?? null,\n 'stages' => [],\n 'currentPipelineId' => $row['pipeline_id'],\n 'currentStage' => [\n 'id' => $row['stage_id'],\n 'enteredAt' => $row['stage_updated_at'],\n ],\n 'currentStageUpdatedAt' => $row['stage_updated_at'],\n 'isClosed' => (bool) $row['is_closed'],\n 'isWon' => (bool) $row['is_won'],\n ];\n\n if (isset($row['owner_uuid'])) {\n $data['owner'] = [\n 'uuid' => RequiresUUID::toNormal($row['owner_uuid']),\n 'name' => $row['owner_name'],\n 'photoUrl' => $row['owner_photo'] === null\n ? null\n : client_cdn($row['owner_photo'], $team),\n 'id' => $row['owner_id'],\n 'job' => $row['owner_job'],\n ];\n }\n\n $result[(int) $row['opp_id']] = $data;\n }\n\n return $this->hydrateStages($result);\n }\n\n private function getSearchSelectAndWhereClauses(QueryBuilder $queryBuilder): QueryBuilder\n {\n $qb = clone $queryBuilder;\n $qb->leftJoin('usr', 'job_titles', 'jt', 'usr.job_title_id = jt.id');\n\n $qb\n ->select(...[\n 'opp.id as opp_id',\n 'opp.uuid',\n 'opp.name',\n 'opp.value',\n 'opp.currency_code',\n 'opp.close_date',\n 'opp.remotely_created_at',\n 'opp.is_closed',\n 'opp.is_won',\n ])\n ->addSelect(...[\n 'usr.uuid as owner_uuid',\n 'usr.name AS owner_name',\n 'usr.photo_path as owner_photo',\n 'usr.id AS owner_id',\n 'jt.name as owner_job',\n ])\n ->addSelect('opp.stage_id', 'opp.stage_updated_at')\n ->addSelect(...[\n 'acc.name AS acc_name',\n 'acc.is_internal as acc_is_internal',\n 'opp.stage_updated_at',\n 'acc.crm_provider_id AS acc_provider_id',\n 'opp.crm_provider_id AS opp_provider_id',\n ])\n ->addSelect('rt.business_process_id AS pipeline_id')\n\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not display deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'));\n\n return $qb;\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws SocialAccountTokenInvalidException\n */\n private function getCrmService(Team $team): ServiceInterface\n {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n $crmService->setConfiguration($team->crm);\n if ($crmService instanceof UrlGeneratorInterface) {\n $crmService->setCrmUrlGenerator($team->crm);\n }\n\n return $crmService;\n }\n\n /**\n *\n * @return Generator<DealData>\n */\n public function getForecastData(DealsFilter $filter): Generator\n {\n $opportunities = DB::query()\n ->select([\n 'o.value',\n 'o.close_date',\n 'o.currency_code',\n 'o.is_won',\n 'o.is_closed',\n 'o.probability',\n 'o.forecast_category',\n ])\n ->from('opportunities', 'o')\n ->join('users', 'users.id', '=', 'o.user_id')\n ->join('groups', 'groups.id', '=', 'users.group_id')\n ->where('users.team_id', $filter->getTeam()->getId())\n ->where('o.close_date', '>=', $filter->getStartDate())\n ->where('o.close_date', '<=', $filter->getEndDate())\n ->where('o.currency_code', $filter->getCurrency())\n ->where('o.deleted_at', '=', null)\n ;\n\n $userUuidList = $filter->getUserUuidList();\n if (! empty($userUuidList)) {\n $userUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $userUuidList);\n\n $opportunities->whereIn('users.uuid', $userUuidList);\n }\n\n $groupUuidList = $filter->getGroupUuidList();\n if (! empty($groupUuidList)) {\n $groupUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $groupUuidList);\n\n $opportunities->whereIn('groups.uuid', $groupUuidList);\n }\n\n foreach ($opportunities->cursor() as $row) {\n yield new DealData(\n (float) $row->value,\n $row->close_date,\n ! empty($row->is_won),\n ! empty($row->is_closed),\n $row->probability ?: 0,\n $row->forecast_category ?: '',\n );\n }\n }\n\n public function getUserOpportunitySubscriptions(User $user, array $opportunityIds): Collection\n {\n return $user->subscriptionSets()\n ->where(static function (Eloquent\\Builder $query): void {\n $query\n ->whereNull('expired_at')\n ->orWhere('expired_at', '>=', now());\n })\n ->join('activity_subscriptions', function (Builder $join) use ($opportunityIds) {\n $join\n ->on('subscription_set_id', '=', 'activity_subscription_sets.id');\n $join\n ->where('followable_type', Models\\Activity\\Subscription::FOLLOWABLE_TYPE_OPPORTUNITY)\n ->whereIn('followable_id', $opportunityIds);\n })\n ->pluck('followable_id');\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAggregator.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAggregatorInterface.php, interface","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"DatabaseActivities.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"DatasourceInterface.php, interface","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"RelatedActivity.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"RelatedActivityInterface.php, interface","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"Commands","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Comments","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Forecast","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Jobs","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"QueryBuilder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Services","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"ClosingPeriodOptionDecorator.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"CreatedPeriodOptionDecorator.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Criteria.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"CriteriaInterface.php, interface","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"CriteriaNormalizer.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"CrmService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"CrmServiceInterface.php, interface","depth":10,"role_description":"text"}]...
|
105273890682564351
|
8406718389801912700
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20157-AJ-report-not-se Project: faVsco.js, menu
JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
12
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Http\Transformers;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Collection;
use Jiminny\Component\Sidekick\SidekickService;
use Jiminny\Exceptions\ActivityProviderException;
use Jiminny\Http\Controllers\Settings\Users\Utils\UserSetting;
use Jiminny\Models\Activity\Provider;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\JobTitle;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Notification\Messengers\MsTeams;
use Jiminny\Services\UserService;
use League\Fractal\Resource;
use League\Fractal\Resource\Item;
use League\Fractal\TransformerAbstract;
class UserTransformer extends TransformerAbstract
{
protected array $availableIncludes = [
'team',
'group',
'job',
'roles',
'permissions',
];
private Container $container;
private bool $withSelfVisibility = false;
public function __construct(?Container $container = null)
{
$this->container = $container ?? app();
}
public function withSelfVisibility(): self
{
$this->withSelfVisibility = true;
return $this;
}
/**
* @throws ActivityProviderException
*
* @return array<string, mixed>
*/
public function transform(User $user): array
{
$attributes = [
'id' => $user->getUuid(),
'name' => $user->getName(),
'firstName' => $user->getFirstName(),
'photoUrl' => $user->getPhotoUrl(),
'conferenceRecordPreference' => $user->checkConferenceRecordPreference(),
'conferenceRecordInternalPreference' => $user->checkConferenceRecordInternalPreference(),
// DO NOT USE User::isCrmRequired as it is not hydrated when fetched from ES!
'crmRequired' => $user->crm_required,
'slackFollowUp' => $user->slack_follow_up,
];
// DO NOT USE User::getId as it is not hydrated when fetched from ES!
if ($this->withSelfVisibility || (auth()->check() && auth()->user()->id === $user->id)) {
$softphoneHasVoiceCapability = $user->hasSoftphoneNumberCapabilities()
&& $user->getSoftphoneNumberCapabilities()->hasVoiceCapability()
;
$conferenceSidekickOpen = $user->getConferenceSidekickOpen();
$softphoneSidekickOpen = $user->getSoftphoneSidekickOpen();
$conferenceSidekickPopupOverridden = false;
$softphoneSidekickPopupOverridden = false;
$hasSidekickEnabled = true;
if ($user->getTeam()->hasFeature(FeatureEnum::SIDEKICK_SETTINGS)) {
$sidekickService = $this->getSidekickService();
$sidekickData = $sidekickService->getSidekickSettingsForUser($user);
$conferenceSidekickOpen = $sidekickData['conferenceSettings'];
$softphoneSidekickOpen = $sidekickData['softphoneSettings'];
$conferenceSidekickPopupOverridden = $sidekickData['conferenceSidekickPopupOverridden'];
$softphoneSidekickPopupOverridden = $sidekickData['softphoneSidekickPopupOverridden'];
$hasSidekickEnabled = $sidekickData['sidekickEnabled'];
}
$userService = $this->getUserService();
$dealInsightsPeriod = $userService->getDealInsightTimelinePeriod($user);
$dataFormatCountryCode = $userService->getDateTimeCountryCode($user);
// Attributes for the user only.
$attributes += [
'conferenceJoinReminder' => $user->conference_join_reminder,
'softphoneInboundRecordPreference' => $user->checkSoftphoneInboundRecordPreference(),
'softphoneOutboundRecordPreference' => $user->checkSoftphoneOutboundRecordPreference(),
'softphoneInboundDestination' => $user->softphone_inbound_destination,
'softphoneHasVoiceCapability' => $softphoneHasVoiceCapability,
'softphoneNumber' => $user->getSoftPhoneNumber(),
'formattedSoftphoneNumber' => $user->getFormattedSoftphoneNumberAttribute(),
'email' => $user->getEmailAddress(),
'secondaryEmail' => $user->getSecondaryEmailAddress(),
'phone' => $user->phone,
'secondaryPhone' => $user->secondary_phone,
'callerId' => $user->getCallerId(),
'countryCode' => $user->getCountryCode(),
'timezone' => $user->getTimezone()->getName(),
'language' => $user->getLanguage(),
'locales' => $this->container->get(UserRepository::class)->getUserLocales($user),
'status' => $user->getStatus(),
'hash' => $user->generateHash(),
'registrationDate' => $user->created_at ? $user->created_at->toIso8601String() : null,
'notifyLiveCoaching' => $user->notify_live_coaching,
'activityLogReminder' => $user->activity_log_reminder,
'conferenceSidekickOpen' => $conferenceSidekickOpen,
'softphoneSidekickOpen' => $softphoneSidekickOpen,
'conferenceSidekickPopupOverridden' => $conferenceSidekickPopupOverridden,
'softphoneSidekickPopupOverridden' => $softphoneSidekickPopupOverridden,
'hasSidekickEnabled' => $hasSidekickEnabled,
'activityActionItems' => $user->activity_action_items,
'syncEmail' => $user->isSyncEmailEnabled(),
'syncConference' => $user->sync_conference,
'syncDialer' => $user->shouldSyncDialer(),
'needsToConfigurePhoneNumber' => $this->container
->get('onboarding_phone_decider')
->isOnboardable($user),
'shouldShowPhoneNumberField' => $this->container
->get('onboarding_phone_decider')
->shouldShowPhoneNumberField($user),
UserSetting::DEAL_INSIGHTS_TIMELINE_PERIOD => $dealInsightsPeriod,
'countryByTimezone' => $dataFormatCountryCode,
'conferenceSlug' => $user->getConferenceSlug(),
'conferenceRecordExternalOrganizerPreference' =>
$userService->isConferenceRecordExternalOrganizerPreferenceEnabled($user),
'hasGeneratedAiReports' => $this->getAutomatedReportsRepository()->countUserReports($user) > 0,
'sendEmailWhenExportLinkIsOpened' => $userService->canSendEmailWhenExportLinkIsOpened($user),
];
if ($user->softphone_debug) {
$attributes += [
'debugSoftphone' => $user->softphone_debug, // Needed?
];
}
}
if ($user->getTeam()->getNotificationProvider() === Team::NOTIFICATION_PROVIDER_MSTEAMS) {
$socialAccountMS = $user->getSocialAccount(Team::CALENDAR_PROVIDER_OFFICE);
$state = $socialAccountMS !== null
? str_contains($socialAccountMS->auth_scope, MsTeams::SCOPE_CHAT_CREATE)
: null;
$attributes['integrations']['office'] = [
'displayName' => 'Microsoft Teams',
'apiName' => 'microsoft-teams',
'types' => ['notification'],
'state' => $state ? Provider::STATE_INSTALLED : Provider::STATE_NOT_INSTALLED,
'logo' => cdn('img/ms-teams-logo.svg'),
'installationStrategy' => 'oauth',
];
}
return $attributes;
}
public function includeTeam(User $user): Item
{
$team = $user->getTeam();
return $this->item($team, $this->getTeamTransformer());
}
public function includeGroup(User $user): ?Item
{
$group = $user->getGroup();
if ($group === null) {
return null;
}
return $this->item($group, $this->getGroupTransformer());
}
public function includeJob(User $user): ?Item
{
$job = $user->getJobTitle();
if (! $job instanceof JobTitle) {
return null;
}
return $this->item($job, $this->getJobTitleTransformer());
}
public function includeRoles(User $user): Resource\Collection
{
/** @var Collection<int, string> $roles */
$roles = $user->roles()
->where('is_visible', true)
->pluck('name')
->toArray();
return $this->collection($roles, $this->getRoleTransformer());
}
public function includePermissions(User $user): Resource\Collection
{
$permissions = $user->allPermissions();
return $this->collection($permissions, $this->getPermissionTransformer());
}
public function includeIntegrations(User $user): Item
{
return $this->item($user, $this->getIntegrationsTransformer());
}
private function getTeamTransformer(): TransformerAbstract
{
return $this->container->get(TeamTransformer::class);
}
private function getGroupTransformer(): GroupTransformer
{
return $this->container->get(GroupTransformer::class);
}
private function getIntegrationsTransformer(): IntegrationTransformer
{
return $this->container->get(IntegrationTransformer::class);
}
private function getPermissionTransformer(): PermissionTransformer
{
return $this->container->get(PermissionTransformer::class);
}
private function getRoleTransformer(): RoleTransformer
{
return $this->container->get(RoleTransformer::class);
}
private function getJobTitleTransformer(): JobTitleTransformer
{
return $this->container->get(JobTitleTransformer::class);
}
private function getSidekickService(): SidekickService
{
/** @var SidekickService */
return $this->container->get(SidekickService::class);
}
private function getUserService(): UserService
{
/** @var UserService */
return $this->container->get(UserService::class);
}
private function getAutomatedReportsRepository(): AutomatedReportsRepository
{
/** @var AutomatedReportsRepository */
return $this->container->get(AutomatedReportsRepository::class);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
36
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\DealInsights;
use Doctrine\DBAL\Connection;
use Generator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Jiminny\Component\DealInsights\Forecast\DealData;
use Jiminny\Component\DealInsights\Forecast\DealsFilter;
use Jiminny\Component\DealInsights\QueryBuilder\QueryBuilder;
use Jiminny\Component\DealInsights\QueryBuilder\Visitor\QueryBuilderVisitorInterface;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Stage;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Models;
use Jiminny\Services\Crm\IntegrationApp\DTO\Utils\UrlGeneratorInterface;
use Jiminny\Services\Crm\ProviderRegistry;
use Jiminny\Traits\RequiresUUID;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Eloquent;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class DealsRepository implements DealsRepositoryInterface
{
private Connection $connection;
private ProviderRegistry $providerRegistry;
/**
* @var QueryBuilderVisitorInterface[]
*/
private array $visitors = [];
/**
* @param QueryBuilderVisitorInterface[] $visitors
*/
public function __construct(Connection $connection, ProviderRegistry $crmProviderRegistry, array $visitors = [])
{
$this->connection = $connection;
$this->providerRegistry = $crmProviderRegistry;
foreach ($visitors as $visitor) {
$this->visitors[$visitor->getIdentifier()] = $visitor;
}
}
public function getDeals(CriteriaInterface $criteria): array
{
$context = $criteria->getContext();
$team = $context->getTeam();
$crmService = $this->getCrmService($team);
$qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);
$qb = $this->getSearchSelectAndWhereClauses($qb);
$this->visit($qb, $criteria);
return $this->execute($team, $crmService, $qb);
}
public function getDeal(Team $team, int $id): array
{
$crmService = $this->getCrmService($team);
$qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);
$qb = $this->getSearchSelectAndWhereClauses($qb);
$qb->andWhere('opp.id = :id')->setParameter('id', $id);
return $this->execute($team, $crmService, $qb);
}
public function getCrmFieldData(array $crmFields, int $crmId, array $opportunityIds = [])
{
$qb = new QueryBuilder($this->connection);
$qb
->select('f.id', 'f.crm_provider_id AS field_name', 'f.label', 'fd.object_id AS dealId', 'fd.value')
->from('crm_fields', 'f')
->join('f', 'crm_field_data', 'fd', 'fd.crm_field_id = f.id')
->where('f.crm_configuration_id = :crm')
->andWhere('f.object_type = :type')
->andWhere('fd.object_id IN (' . implode(',', $opportunityIds) . ')')
->orderBy('fd.object_id', 'ASC')
->addOrderBy('fd.updated_at', 'ASC')
->setParameter('type', Field::OBJECT_OPPORTUNITY)
->setParameter('crm', $crmId)
;
if (! empty($crmFields)) {
$fields = array_map(fn ($value): string => '"' . $value . '"', $crmFields);
$qb->andWhere('f.crm_provider_id IN (' . implode(',', $fields) . ')');
}
return $qb->executeQuery()->fetchAllAssociative();
}
public function getTotalsInDefaultCurrency(CriteriaInterface $criteria): array
{
$qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);
$qb
->select('SUM(opp.value) as total')
->addSelect('count(*) as `count`')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'))
;
$this->visit($qb, $criteria);
return $qb->executeQuery()->fetchAssociative();
}
public function getTotals(CriteriaInterface $criteria, string $defaultCurrency): array
{
$qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);
$qb
->select('COALESCE(opp.currency_code, "' . $defaultCurrency . '") AS currency')
->addSelect('SUM(opp.value) as total')
->addSelect('count(*) as `count`')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'))
->groupBy('currency')
;
$this->visit($qb, $criteria);
return $qb->executeQuery()->fetchAllAssociative();
}
public function getDealActivities(CriteriaInterface $criteria): array
{
$qb = Activity::with(['participants', 'user'])
->where('opportunity_id', $criteria->getOpportunityId())
->whereDate('actual_start_time', '>=', $criteria->getPeriod()->getStartDate())
->whereDate('actual_start_time', '<=', $criteria->getPeriod()->getEndDate())
->orderBy($criteria->getSortBy(), $criteria->getSortDirection())
;
// Should we filter activities by criteria? It's intended to filter deals.
return $qb->get()->all();
}
public function getStages(CriteriaInterface $criteria): array
{
$qb = new QueryBuilder($this->connection);
$qb
->select('id', 'label', 'sequence')
->from('stages', 's')
->where('crm_configuration_id = :crm_configuration_id')
->andWhere('type = :type')
->orderBy('sequence', 'ASC')
->setParameter('crm_configuration_id', $criteria->getContext()->getTeam()->getCrmConfiguration()->getId())
->setParameter('type', Stage::TYPE_OPPORTUNITY);
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$result[$row['id']] = [
'label' => $row['label'],
'sequence' => $row['sequence'],
];
}
return $result;
}
public function getConfigurationStages(Configuration $configuration): Collection
{
return $configuration
->stages()
->where('type', Stage::TYPE_OPPORTUNITY)
->get();
}
public function getPipelineData(Configuration $crm): array
{
$qb = new QueryBuilder($this->connection);
$provider = $crm->provider;
$qb
->select('s.label', 's.crm_provider_id', 's.sequence', 'bps.business_process_id AS pipeline_id')
->from('stages', 's')
->join('s', 'business_process_stages', 'bps', 's.id=bps.stage_id')
->where('s.crm_configuration_id = :crm_configuration_id')
->andWhere('s.type = :type')
->orderBy('bps.business_process_id', 'ASC')
->addOrderBy('s.sequence', 'ASC')
->setParameter('crm_configuration_id', $crm->id)
->setParameter('type', Stage::TYPE_OPPORTUNITY)
;
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$value = $provider === Configuration::PROVIDER_SALESFORCE ? $row['label'] : $row['crm_provider_id'];
$result[$row['pipeline_id']][] = [
'value' => $value,
'label' => $row['label'],
'sequence' => $row['sequence'],
];
}
return $result;
}
private function createQueryBuilder(string $realm): QueryBuilder
{
return (new QueryBuilder($this->connection))
->setRealm($realm)
->from('opportunities', 'opp')
->leftJoin('opp', 'record_types', 'rt', 'opp.record_type_id = rt.id')
->leftJoin('opp', 'users', 'usr', 'opp.user_id = usr.id')
->leftJoin('opp', 'accounts', 'acc', 'opp.account_id = acc.id')
;
}
/**
* Applies all applicable visitors and returns the IDs of the executed ones
*
* @return string[]
*/
private function visit(QueryBuilder $queryBuilder, CriteriaInterface $criteria): array
{
$queryVisitors = [];
foreach ($this->visitors as $visitor) {
if ($visitor->isSatisfiedBy($criteria, $queryBuilder->getRealm())) {
$visitor->visit($queryBuilder, $criteria);
$queryVisitors[] = $visitor->getIdentifier();
}
}
return $queryVisitors;
}
private function hydrateStages(array $deals): array
{
foreach ($this->fetchStages(array_keys($deals)) as $stage) {
$oppId = (int) $stage['opportunity_id'];
if (! isset($deals[$oppId])) {
continue; // or throw??!
}
$deals[$oppId]['stages'][] = [
'id' => $stage['stage_id'],
'name' => $stage['label'],
'enteredAt' => $stage['created_at'],
];
}
return $deals;
}
/**
* @param int[] $dealIds
*/
private function fetchStages(array $dealIds): array
{
if (empty($dealIds)) {
return [];
}
$qb = new QueryBuilder($this->connection);
$qb
->select('os.opportunity_id', 's.id AS stage_id', 's.label', 's.created_at')
->from('opportunity_stages', 'os')
->leftJoin('os', 'stages', 's', 'os.stage_id=s.id')
->where($qb->expr()->in('os.opportunity_id', $dealIds))
->orderBy('os.opportunity_id', 'ASC')
->addOrderBy('s.created_at', 'ASC')
;
return $qb->executeQuery()->fetchAllAssociative();
}
private function execute(Team $team, ServiceInterface $crmService, QueryBuilder $qb): array
{
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$data = [
'uuid' => RequiresUUID::toNormal($row['uuid']),
'name' => $row['name'],
'url' => $crmService->generateProviderUrl($row['opp_provider_id'], 'opportunity'),
'account' => [
'name' => $row['acc_name'],
'url' => $crmService->generateProviderUrl(
providerId: $row['acc_provider_id'],
objectType: $row['acc_is_internal'] ? 'internal-account' : 'account'
),
],
'owner' => null,
'rawValue' => [
'amount' => (float) $row['value'],
'currency' => $row['currency_code'],
],
'value' => formatOpportunityValue((float) $row['value'], $row['currency_code']),
'openDate' => $row['remotely_created_at'] ?? null,
'closeDate' => $row['close_date'] ?? null,
'stages' => [],
'currentPipelineId' => $row['pipeline_id'],
'currentStage' => [
'id' => $row['stage_id'],
'enteredAt' => $row['stage_updated_at'],
],
'currentStageUpdatedAt' => $row['stage_updated_at'],
'isClosed' => (bool) $row['is_closed'],
'isWon' => (bool) $row['is_won'],
];
if (isset($row['owner_uuid'])) {
$data['owner'] = [
'uuid' => RequiresUUID::toNormal($row['owner_uuid']),
'name' => $row['owner_name'],
'photoUrl' => $row['owner_photo'] === null
? null
: client_cdn($row['owner_photo'], $team),
'id' => $row['owner_id'],
'job' => $row['owner_job'],
];
}
$result[(int) $row['opp_id']] = $data;
}
return $this->hydrateStages($result);
}
private function getSearchSelectAndWhereClauses(QueryBuilder $queryBuilder): QueryBuilder
{
$qb = clone $queryBuilder;
$qb->leftJoin('usr', 'job_titles', 'jt', 'usr.job_title_id = jt.id');
$qb
->select(...[
'opp.id as opp_id',
'opp.uuid',
'opp.name',
'opp.value',
'opp.currency_code',
'opp.close_date',
'opp.remotely_created_at',
'opp.is_closed',
'opp.is_won',
])
->addSelect(...[
'usr.uuid as owner_uuid',
'usr.name AS owner_name',
'usr.photo_path as owner_photo',
'usr.id AS owner_id',
'jt.name as owner_job',
])
->addSelect('opp.stage_id', 'opp.stage_updated_at')
->addSelect(...[
'acc.name AS acc_name',
'acc.is_internal as acc_is_internal',
'opp.stage_updated_at',
'acc.crm_provider_id AS acc_provider_id',
'opp.crm_provider_id AS opp_provider_id',
])
->addSelect('rt.business_process_id AS pipeline_id')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not display deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'));
return $qb;
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws SocialAccountTokenInvalidException
*/
private function getCrmService(Team $team): ServiceInterface
{
$crmService = $this->providerRegistry->get($team->crm->provider);
$crmService->setConfiguration($team->crm);
if ($crmService instanceof UrlGeneratorInterface) {
$crmService->setCrmUrlGenerator($team->crm);
}
return $crmService;
}
/**
*
* @return Generator<DealData>
*/
public function getForecastData(DealsFilter $filter): Generator
{
$opportunities = DB::query()
->select([
'o.value',
'o.close_date',
'o.currency_code',
'o.is_won',
'o.is_closed',
'o.probability',
'o.forecast_category',
])
->from('opportunities', 'o')
->join('users', 'users.id', '=', 'o.user_id')
->join('groups', 'groups.id', '=', 'users.group_id')
->where('users.team_id', $filter->getTeam()->getId())
->where('o.close_date', '>=', $filter->getStartDate())
->where('o.close_date', '<=', $filter->getEndDate())
->where('o.currency_code', $filter->getCurrency())
->where('o.deleted_at', '=', null)
;
$userUuidList = $filter->getUserUuidList();
if (! empty($userUuidList)) {
$userUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $userUuidList);
$opportunities->whereIn('users.uuid', $userUuidList);
}
$groupUuidList = $filter->getGroupUuidList();
if (! empty($groupUuidList)) {
$groupUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $groupUuidList);
$opportunities->whereIn('groups.uuid', $groupUuidList);
}
foreach ($opportunities->cursor() as $row) {
yield new DealData(
(float) $row->value,
$row->close_date,
! empty($row->is_won),
! empty($row->is_closed),
$row->probability ?: 0,
$row->forecast_category ?: '',
);
}
}
public function getUserOpportunitySubscriptions(User $user, array $opportunityIds): Collection
{
return $user->subscriptionSets()
->where(static function (Eloquent\Builder $query): void {
$query
->whereNull('expired_at')
->orWhere('expired_at', '>=', now());
})
->join('activity_subscriptions', function (Builder $join) use ($opportunityIds) {
$join
->on('subscription_set_id', '=', 'activity_subscription_sets.id');
$join
->where('followable_type', Models\Activity\Subscription::FOLLOWABLE_TYPE_OPPORTUNITY)
->whereIn('followable_id', $opportunityIds);
})
->pluck('followable_id');
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
Activity
ActivityAggregator.php, class
ActivityAggregatorInterface.php, interface
DatabaseActivities.php, class
DatasourceInterface.php, interface
RelatedActivity.php, class
RelatedActivityInterface.php, interface
Commands
Comments
Forecast
Jobs
QueryBuilder
Services
ClosingPeriodOptionDecorator.php, class
CreatedPeriodOptionDecorator.php, class
Criteria.php, class
CriteriaInterface.php, interface
CriteriaNormalizer.php, class
CrmService.php, class
CrmServiceInterface.php, interface...
|
NULL
|
|
72871
|
1778
|
8
|
2026-04-23T06:20:22.962337+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-23/1776 /Users/lukas/.screenpipe/data/data/2026-04-23/1776925222962_m1.jpg...
|
PhpStorm
|
faVsco.js – UserTransformer.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20157-AJ-report-not-se Project: faVsco.js, menu
JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
13
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Http\Transformers;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Collection;
use Jiminny\Component\Sidekick\SidekickService;
use Jiminny\Exceptions\ActivityProviderException;
use Jiminny\Http\Controllers\Settings\Users\Utils\UserSetting;
use Jiminny\Models\Activity\Provider;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\JobTitle;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Notification\Messengers\MsTeams;
use Jiminny\Services\UserService;
use League\Fractal\Resource;
use League\Fractal\Resource\Item;
use League\Fractal\TransformerAbstract;
class UserTransformer extends TransformerAbstract
{
protected array $availableIncludes = [
'team',
'group',
'job',
'roles',
'permissions',
];
private Container $container;
private bool $withSelfVisibility = false;
public function __construct(?Container $container = null)
{
$this->container = $container ?? app();
}
public function withSelfVisibility(): self
{
$this->withSelfVisibility = true;
return $this;
}
/**
* @throws ActivityProviderException
*
* @return array<string, mixed>
*/
public function transform(User $user): array
{
$attributes = [
'id' => $user->getUuid(),
'name' => $user->getName(),
'firstName' => $user->getFirstName(),
'photoUrl' => $user->getPhotoUrl(),
'conferenceRecordPreference' => $user->checkConferenceRecordPreference(),
'conferenceRecordInternalPreference' => $user->checkConferenceRecordInternalPreference(),
// DO NOT USE User::isCrmRequired as it is not hydrated when fetched from ES!
'crmRequired' => $user->crm_required,
'slackFollowUp' => $user->slack_follow_up,
];
// DO NOT USE User::getId as it is not hydrated when fetched from ES!
if ($this->withSelfVisibility || (auth()->check() && auth()->user()->id === $user->id)) {
$softphoneHasVoiceCapability = $user->hasSoftphoneNumberCapabilities()
&& $user->getSoftphoneNumberCapabilities()->hasVoiceCapability()
;
$conferenceSidekickOpen = $user->getConferenceSidekickOpen();
$softphoneSidekickOpen = $user->getSoftphoneSidekickOpen();
$conferenceSidekickPopupOverridden = false;
$softphoneSidekickPopupOverridden = false;
$hasSidekickEnabled = true;
if ($user->getTeam()->hasFeature(FeatureEnum::SIDEKICK_SETTINGS)) {
$sidekickService = $this->getSidekickService();
$sidekickData = $sidekickService->getSidekickSettingsForUser($user);
$conferenceSidekickOpen = $sidekickData['conferenceSettings'];
$softphoneSidekickOpen = $sidekickData['softphoneSettings'];
$conferenceSidekickPopupOverridden = $sidekickData['conferenceSidekickPopupOverridden'];
$softphoneSidekickPopupOverridden = $sidekickData['softphoneSidekickPopupOverridden'];
$hasSidekickEnabled = $sidekickData['sidekickEnabled'];
}
$userService = $this->getUserService();
$dealInsightsPeriod = $userService->getDealInsightTimelinePeriod($user);
$dataFormatCountryCode = $userService->getDateTimeCountryCode($user);
// Attributes for the user only.
$attributes += [
'conferenceJoinReminder' => $user->conference_join_reminder,
'softphoneInboundRecordPreference' => $user->checkSoftphoneInboundRecordPreference(),
'softphoneOutboundRecordPreference' => $user->checkSoftphoneOutboundRecordPreference(),
'softphoneInboundDestination' => $user->softphone_inbound_destination,
'softphoneHasVoiceCapability' => $softphoneHasVoiceCapability,
'softphoneNumber' => $user->getSoftPhoneNumber(),
'formattedSoftphoneNumber' => $user->getFormattedSoftphoneNumberAttribute(),
'email' => $user->getEmailAddress(),
'secondaryEmail' => $user->getSecondaryEmailAddress(),
'phone' => $user->phone,
'secondaryPhone' => $user->secondary_phone,
'callerId' => $user->getCallerId(),
'countryCode' => $user->getCountryCode(),
'timezone' => $user->getTimezone()->getName(),
'language' => $user->getLanguage(),
'locales' => $this->container->get(UserRepository::class)->getUserLocales($user),
'status' => $user->getStatus(),
'hash' => $user->generateHash(),
'registrationDate' => $user->created_at ? $user->created_at->toIso8601String() : null,
'notifyLiveCoaching' => $user->notify_live_coaching,
'activityLogReminder' => $user->activity_log_reminder,
'conferenceSidekickOpen' => $conferenceSidekickOpen,
'softphoneSidekickOpen' => $softphoneSidekickOpen,
'conferenceSidekickPopupOverridden' => $conferenceSidekickPopupOverridden,
'softphoneSidekickPopupOverridden' => $softphoneSidekickPopupOverridden,
'hasSidekickEnabled' => $hasSidekickEnabled,
'activityActionItems' => $user->activity_action_items,
'syncEmail' => $user->isSyncEmailEnabled(),
'syncConference' => $user->sync_conference,
'syncDialer' => $user->shouldSyncDialer(),
'needsToConfigurePhoneNumber' => $this->container
->get('onboarding_phone_decider')
->isOnboardable($user),
'shouldShowPhoneNumberField' => $this->container
->get('onboarding_phone_decider')
->shouldShowPhoneNumberField($user),
UserSetting::DEAL_INSIGHTS_TIMELINE_PERIOD => $dealInsightsPeriod,
'countryByTimezone' => $dataFormatCountryCode,
'conferenceSlug' => $user->getConferenceSlug(),
'conferenceRecordExternalOrganizerPreference' =>
$userService->isConferenceRecordExternalOrganizerPreferenceEnabled($user),
'hasGeneratedAiReports' => $this->getAutomatedReportsRepository()->countUserReports($user) > 0,
'sendEmailWhenExportLinkIsOpened' => $userService->canSendEmailWhenExportLinkIsOpened($user),
];
if ($user->softphone_debug) {
$attributes += [
'debugSoftphone' => $user->softphone_debug, // Needed?
];
}
}
if ($user->getTeam()->getNotificationProvider() === Team::NOTIFICATION_PROVIDER_MSTEAMS) {
$socialAccountMS = $user->getSocialAccount(Team::CALENDAR_PROVIDER_OFFICE);
$state = $socialAccountMS !== null
? str_contains($socialAccountMS->auth_scope, MsTeams::SCOPE_CHAT_CREATE)
: null;
$attributes['integrations']['office'] = [
'displayName' => 'Microsoft Teams',
'apiName' => 'microsoft-teams',
'types' => ['notification'],
'state' => $state ? Provider::STATE_INSTALLED : Provider::STATE_NOT_INSTALLED,
'logo' => cdn('img/ms-teams-logo.svg'),
'installationStrategy' => 'oauth',
];
}
return $attributes;
}
public function includeTeam(User $user): Item
{
$team = $user->getTeam();
return $this->item($team, $this->getTeamTransformer());
}
public function includeGroup(User $user): ?Item
{
$group = $user->getGroup();
if ($group === null) {
return null;
}
return $this->item($group, $this->getGroupTransformer());
}
public function includeJob(User $user): ?Item
{
$job = $user->getJobTitle();
if (! $job instanceof JobTitle) {
return null;
}
return $this->item($job, $this->getJobTitleTransformer());
}
public function includeRoles(User $user): Resource\Collection
{
/** @var Collection<int, string> $roles */
$roles = $user->roles()
->where('is_visible', true)
->pluck('name')
->toArray();
return $this->collection($roles, $this->getRoleTransformer());
}
public function includePermissions(User $user): Resource\Collection
{
$permissions = $user->allPermissions();
return $this->collection($permissions, $this->getPermissionTransformer());
}
public function includeIntegrations(User $user): Item
{
return $this->item($user, $this->getIntegrationsTransformer());
}
private function getTeamTransformer(): TransformerAbstract
{
return $this->container->get(TeamTransformer::class);
}
private function getGroupTransformer(): GroupTransformer
{
return $this->container->get(GroupTransformer::class);
}
private function getIntegrationsTransformer(): IntegrationTransformer
{
return $this->container->get(IntegrationTransformer::class);
}
private function getPermissionTransformer(): PermissionTransformer
{
return $this->container->get(PermissionTransformer::class);
}
private function getRoleTransformer(): RoleTransformer
{
return $this->container->get(RoleTransformer::class);
}
private function getJobTitleTransformer(): JobTitleTransformer
{
return $this->container->get(JobTitleTransformer::class);
}
private function getSidekickService(): SidekickService
{
/** @var SidekickService */
return $this->container->get(SidekickService::class);
}
private function getUserService(): UserService
{
/** @var UserService */
return $this->container->get(UserService::class);
}
private function getAutomatedReportsRepository(): AutomatedReportsRepository
{
/** @var AutomatedReportsRepository */
return $this->container->get(AutomatedReportsRepository::class);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
36
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\DealInsights;
use Doctrine\DBAL\Connection;
use Generator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Jiminny\Component\DealInsights\Forecast\DealData;
use Jiminny\Component\DealInsights\Forecast\DealsFilter;
use Jiminny\Component\DealInsights\QueryBuilder\QueryBuilder;
use Jiminny\Component\DealInsights\QueryBuilder\Visitor\QueryBuilderVisitorInterface;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Stage;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Models;
use Jiminny\Services\Crm\IntegrationApp\DTO\Utils\UrlGeneratorInterface;
use Jiminny\Services\Crm\ProviderRegistry;
use Jiminny\Traits\RequiresUUID;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Eloquent;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class DealsRepository implements DealsRepositoryInterface
{
private Connection $connection;
private ProviderRegistry $providerRegistry;
/**
* @var QueryBuilderVisitorInterface[]
*/
private array $visitors = [];
/**
* @param QueryBuilderVisitorInterface[] $visitors
*/
public function __construct(Connection $connection, ProviderRegistry $crmProviderRegistry, array $visitors = [])
{
$this->connection = $connection;
$this->providerRegistry = $crmProviderRegistry;
foreach ($visitors as $visitor) {
$this->visitors[$visitor->getIdentifier()] = $visitor;
}
}
public function getDeals(CriteriaInterface $criteria): array
{
$context = $criteria->getContext();
$team = $context->getTeam();
$crmService = $this->getCrmService($team);
$qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);
$qb = $this->getSearchSelectAndWhereClauses($qb);
$this->visit($qb, $criteria);
return $this->execute($team, $crmService, $qb);
}
public function getDeal(Team $team, int $id): array
{
$crmService = $this->getCrmService($team);
$qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);
$qb = $this->getSearchSelectAndWhereClauses($qb);
$qb->andWhere('opp.id = :id')->setParameter('id', $id);
return $this->execute($team, $crmService, $qb);
}
public function getCrmFieldData(array $crmFields, int $crmId, array $opportunityIds = [])
{
$qb = new QueryBuilder($this->connection);
$qb
->select('f.id', 'f.crm_provider_id AS field_name', 'f.label', 'fd.object_id AS dealId', 'fd.value')
->from('crm_fields', 'f')
->join('f', 'crm_field_data', 'fd', 'fd.crm_field_id = f.id')
->where('f.crm_configuration_id = :crm')
->andWhere('f.object_type = :type')
->andWhere('fd.object_id IN (' . implode(',', $opportunityIds) . ')')
->orderBy('fd.object_id', 'ASC')
->addOrderBy('fd.updated_at', 'ASC')
->setParameter('type', Field::OBJECT_OPPORTUNITY)
->setParameter('crm', $crmId)
;
if (! empty($crmFields)) {
$fields = array_map(fn ($value): string => '"' . $value . '"', $crmFields);
$qb->andWhere('f.crm_provider_id IN (' . implode(',', $fields) . ')');
}
return $qb->executeQuery()->fetchAllAssociative();
}
public function getTotalsInDefaultCurrency(CriteriaInterface $criteria): array
{
$qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);
$qb
->select('SUM(opp.value) as total')
->addSelect('count(*) as `count`')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'))
;
$this->visit($qb, $criteria);
return $qb->executeQuery()->fetchAssociative();
}
public function getTotals(CriteriaInterface $criteria, string $defaultCurrency): array
{
$qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);
$qb
->select('COALESCE(opp.currency_code, "' . $defaultCurrency . '") AS currency')
->addSelect('SUM(opp.value) as total')
->addSelect('count(*) as `count`')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'))
->groupBy('currency')
;
$this->visit($qb, $criteria);
return $qb->executeQuery()->fetchAllAssociative();
}
public function getDealActivities(CriteriaInterface $criteria): array
{
$qb = Activity::with(['participants', 'user'])
->where('opportunity_id', $criteria->getOpportunityId())
->whereDate('actual_start_time', '>=', $criteria->getPeriod()->getStartDate())
->whereDate('actual_start_time', '<=', $criteria->getPeriod()->getEndDate())
->orderBy($criteria->getSortBy(), $criteria->getSortDirection())
;
// Should we filter activities by criteria? It's intended to filter deals.
return $qb->get()->all();
}
public function getStages(CriteriaInterface $criteria): array
{
$qb = new QueryBuilder($this->connection);
$qb
->select('id', 'label', 'sequence')
->from('stages', 's')
->where('crm_configuration_id = :crm_configuration_id')
->andWhere('type = :type')
->orderBy('sequence', 'ASC')
->setParameter('crm_configuration_id', $criteria->getContext()->getTeam()->getCrmConfiguration()->getId())
->setParameter('type', Stage::TYPE_OPPORTUNITY);
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$result[$row['id']] = [
'label' => $row['label'],
'sequence' => $row['sequence'],
];
}
return $result;
}
public function getConfigurationStages(Configuration $configuration): Collection
{
return $configuration
->stages()
->where('type', Stage::TYPE_OPPORTUNITY)
->get();
}
public function getPipelineData(Configuration $crm): array
{
$qb = new QueryBuilder($this->connection);
$provider = $crm->provider;
$qb
->select('s.label', 's.crm_provider_id', 's.sequence', 'bps.business_process_id AS pipeline_id')
->from('stages', 's')
->join('s', 'business_process_stages', 'bps', 's.id=bps.stage_id')
->where('s.crm_configuration_id = :crm_configuration_id')
->andWhere('s.type = :type')
->orderBy('bps.business_process_id', 'ASC')
->addOrderBy('s.sequence', 'ASC')
->setParameter('crm_configuration_id', $crm->id)
->setParameter('type', Stage::TYPE_OPPORTUNITY)
;
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$value = $provider === Configuration::PROVIDER_SALESFORCE ? $row['label'] : $row['crm_provider_id'];
$result[$row['pipeline_id']][] = [
'value' => $value,
'label' => $row['label'],
'sequence' => $row['sequence'],
];
}
return $result;
}
private function createQueryBuilder(string $realm): QueryBuilder
{
return (new QueryBuilder($this->connection))
->setRealm($realm)
->from('opportunities', 'opp')
->leftJoin('opp', 'record_types', 'rt', 'opp.record_type_id = rt.id')
->leftJoin('opp', 'users', 'usr', 'opp.user_id = usr.id')
->leftJoin('opp', 'accounts', 'acc', 'opp.account_id = acc.id')
;
}
/**
* Applies all applicable visitors and returns the IDs of the executed ones
*
* @return string[]
*/
private function visit(QueryBuilder $queryBuilder, CriteriaInterface $criteria): array
{
$queryVisitors = [];
foreach ($this->visitors as $visitor) {
if ($visitor->isSatisfiedBy($criteria, $queryBuilder->getRealm())) {
$visitor->visit($queryBuilder, $criteria);
$queryVisitors[] = $visitor->getIdentifier();
}
}
return $queryVisitors;
}
private function hydrateStages(array $deals): array
{
foreach ($this->fetchStages(array_keys($deals)) as $stage) {
$oppId = (int) $stage['opportunity_id'];
if (! isset($deals[$oppId])) {
continue; // or throw??!
}
$deals[$oppId]['stages'][] = [
'id' => $stage['stage_id'],
'name' => $stage['label'],
'enteredAt' => $stage['created_at'],
];
}
return $deals;
}
/**
* @param int[] $dealIds
*/
private function fetchStages(array $dealIds): array
{
if (empty($dealIds)) {
return [];
}
$qb = new QueryBuilder($this->connection);
$qb
->select('os.opportunity_id', 's.id AS stage_id', 's.label', 's.created_at')
->from('opportunity_stages', 'os')
->leftJoin('os', 'stages', 's', 'os.stage_id=s.id')
->where($qb->expr()->in('os.opportunity_id', $dealIds))
->orderBy('os.opportunity_id', 'ASC')
->addOrderBy('s.created_at', 'ASC')
;
return $qb->executeQuery()->fetchAllAssociative();
}
private function execute(Team $team, ServiceInterface $crmService, QueryBuilder $qb): array
{
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$data = [
'uuid' => RequiresUUID::toNormal($row['uuid']),
'name' => $row['name'],
'url' => $crmService->generateProviderUrl($row['opp_provider_id'], 'opportunity'),
'account' => [
'name' => $row['acc_name'],
'url' => $crmService->generateProviderUrl(
providerId: $row['acc_provider_id'],
objectType: $row['acc_is_internal'] ? 'internal-account' : 'account'
),
],
'owner' => null,
'rawValue' => [
'amount' => (float) $row['value'],
'currency' => $row['currency_code'],
],
'value' => formatOpportunityValue((float) $row['value'], $row['currency_code']),
'openDate' => $row['remotely_created_at'] ?? null,
'closeDate' => $row['close_date'] ?? null,
'stages' => [],
'currentPipelineId' => $row['pipeline_id'],
'currentStage' => [
'id' => $row['stage_id'],
'enteredAt' => $row['stage_updated_at'],
],
'currentStageUpdatedAt' => $row['stage_updated_at'],
'isClosed' => (bool) $row['is_closed'],
'isWon' => (bool) $row['is_won'],
];
if (isset($row['owner_uuid'])) {
$data['owner'] = [
'uuid' => RequiresUUID::toNormal($row['owner_uuid']),
'name' => $row['owner_name'],
'photoUrl' => $row['owner_photo'] === null
? null
: client_cdn($row['owner_photo'], $team),
'id' => $row['owner_id'],
'job' => $row['owner_job'],
];
}
$result[(int) $row['opp_id']] = $data;
}
return $this->hydrateStages($result);
}
private function getSearchSelectAndWhereClauses(QueryBuilder $queryBuilder): QueryBuilder
{
$qb = clone $queryBuilder;
$qb->leftJoin('usr', 'job_titles', 'jt', 'usr.job_title_id = jt.id');
$qb
->select(...[
'opp.id as opp_id',
'opp.uuid',
'opp.name',
'opp.value',
'opp.currency_code',
'opp.close_date',
'opp.remotely_created_at',
'opp.is_closed',
'opp.is_won',
])
->addSelect(...[
'usr.uuid as owner_uuid',
'usr.name AS owner_name',
'usr.photo_path as owner_photo',
'usr.id AS owner_id',
'jt.name as owner_job',
])
->addSelect('opp.stage_id', 'opp.stage_updated_at')
->addSelect(...[
'acc.name AS acc_name',
'acc.is_internal as acc_is_internal',
'opp.stage_updated_at',
'acc.crm_provider_id AS acc_provider_id',
'opp.crm_provider_id AS opp_provider_id',
])
->addSelect('rt.business_process_id AS pipeline_id')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not display deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'));
return $qb;
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws SocialAccountTokenInvalidException
*/
private function getCrmService(Team $team): ServiceInterface
{
$crmService = $this->providerRegistry->get($team->crm->provider);
$crmService->setConfiguration($team->crm);
if ($crmService instanceof UrlGeneratorInterface) {
$crmService->setCrmUrlGenerator($team->crm);
}
return $crmService;
}
/**
*
* @return Generator<DealData>
*/
public function getForecastData(DealsFilter $filter): Generator
{
$opportunities = DB::query()
->select([
'o.value',
'o.close_date',
'o.currency_code',
'o.is_won',
'o.is_closed',
'o.probability',
'o.forecast_category',
])
->from('opportunities', 'o')
->join('users', 'users.id', '=', 'o.user_id')
->join('groups', 'groups.id', '=', 'users.group_id')
->where('users.team_id', $filter->getTeam()->getId())
->where('o.close_date', '>=', $filter->getStartDate())
->where('o.close_date', '<=', $filter->getEndDate())
->where('o.currency_code', $filter->getCurrency())
->where('o.deleted_at', '=', null)
;
$userUuidList = $filter->getUserUuidList();
if (! empty($userUuidList)) {
$userUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $userUuidList);
$opportunities->whereIn('users.uuid', $userUuidList);
}
$groupUuidList = $filter->getGroupUuidList();
if (! empty($groupUuidList)) {
$groupUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $groupUuidList);
$opportunities->whereIn('groups.uuid', $groupUuidList);
}
foreach ($opportunities->cursor() as $row) {
yield new DealData(
(float) $row->value,
$row->close_date,
! empty($row->is_won),
! empty($row->is_closed),
$row->probability ?: 0,
$row->forecast_category ?: '',
);
}
}
public function getUserOpportunitySubscriptions(User $user, array $opportunityIds): Collection
{
return $user->subscriptionSets()
->where(static function (Eloquent\Builder $query): void {
$query
->whereNull('expired_at')
->orWhere('expired_at', '>=', now());
})
->join('activity_subscriptions', function (Builder $join) use ($opportunityIds) {
$join
->on('subscription_set_id', '=', 'activity_subscription_sets.id');
$join
->where('followable_type', Models\Activity\Subscription::FOLLOWABLE_TYPE_OPPORTUNITY)
->whereIn('followable_id', $opportunityIds);
})
->pluck('followable_id');
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
Activity
ActivityAggregator.php, class
ActivityAggregatorInterface.php, interface
DatabaseActivities.php, class
DatasourceInterface.php, interface
RelatedActivity.php, class
RelatedActivityInterface.php, interface
Commands
Comments
Forecast
Jobs
QueryBuilder
Services
ClosingPeriodOptionDecorator.php, class
CreatedPeriodOptionDecorator.php, class
Criteria.php, class
CriteriaInterface.php, interface
CriteriaNormalizer.php, class
CrmService.php, class
CrmServiceInterface.php, interface
DealContactService.php, class
DealInsightsCriteriaBuilder.php, class
DealService.php, class
DealServiceInterface.php, interface
DealsRepository.php, class
DealsRepositoryInterface.php, interface...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Git Branch: JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"RequestGenerateAskJiminnyReportJobTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"13","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Http\\Transformers;\n\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\Sidekick\\SidekickService;\nuse Jiminny\\Exceptions\\ActivityProviderException;\nuse Jiminny\\Http\\Controllers\\Settings\\Users\\Utils\\UserSetting;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\JobTitle;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Notification\\Messengers\\MsTeams;\nuse Jiminny\\Services\\UserService;\nuse League\\Fractal\\Resource;\nuse League\\Fractal\\Resource\\Item;\nuse League\\Fractal\\TransformerAbstract;\n\nclass UserTransformer extends TransformerAbstract\n{\n protected array $availableIncludes = [\n 'team',\n 'group',\n 'job',\n 'roles',\n 'permissions',\n ];\n\n private Container $container;\n\n private bool $withSelfVisibility = false;\n\n public function __construct(?Container $container = null)\n {\n $this->container = $container ?? app();\n }\n\n public function withSelfVisibility(): self\n {\n $this->withSelfVisibility = true;\n\n return $this;\n }\n\n /**\n * @throws ActivityProviderException\n *\n * @return array<string, mixed>\n */\n public function transform(User $user): array\n {\n $attributes = [\n 'id' => $user->getUuid(),\n 'name' => $user->getName(),\n 'firstName' => $user->getFirstName(),\n 'photoUrl' => $user->getPhotoUrl(),\n 'conferenceRecordPreference' => $user->checkConferenceRecordPreference(),\n 'conferenceRecordInternalPreference' => $user->checkConferenceRecordInternalPreference(),\n // DO NOT USE User::isCrmRequired as it is not hydrated when fetched from ES!\n 'crmRequired' => $user->crm_required,\n 'slackFollowUp' => $user->slack_follow_up,\n ];\n\n // DO NOT USE User::getId as it is not hydrated when fetched from ES!\n if ($this->withSelfVisibility || (auth()->check() && auth()->user()->id === $user->id)) {\n $softphoneHasVoiceCapability = $user->hasSoftphoneNumberCapabilities()\n && $user->getSoftphoneNumberCapabilities()->hasVoiceCapability()\n ;\n\n $conferenceSidekickOpen = $user->getConferenceSidekickOpen();\n $softphoneSidekickOpen = $user->getSoftphoneSidekickOpen();\n $conferenceSidekickPopupOverridden = false;\n $softphoneSidekickPopupOverridden = false;\n $hasSidekickEnabled = true;\n\n if ($user->getTeam()->hasFeature(FeatureEnum::SIDEKICK_SETTINGS)) {\n $sidekickService = $this->getSidekickService();\n\n $sidekickData = $sidekickService->getSidekickSettingsForUser($user);\n\n $conferenceSidekickOpen = $sidekickData['conferenceSettings'];\n $softphoneSidekickOpen = $sidekickData['softphoneSettings'];\n $conferenceSidekickPopupOverridden = $sidekickData['conferenceSidekickPopupOverridden'];\n $softphoneSidekickPopupOverridden = $sidekickData['softphoneSidekickPopupOverridden'];\n $hasSidekickEnabled = $sidekickData['sidekickEnabled'];\n }\n\n $userService = $this->getUserService();\n $dealInsightsPeriod = $userService->getDealInsightTimelinePeriod($user);\n $dataFormatCountryCode = $userService->getDateTimeCountryCode($user);\n\n // Attributes for the user only.\n $attributes += [\n 'conferenceJoinReminder' => $user->conference_join_reminder,\n 'softphoneInboundRecordPreference' => $user->checkSoftphoneInboundRecordPreference(),\n 'softphoneOutboundRecordPreference' => $user->checkSoftphoneOutboundRecordPreference(),\n 'softphoneInboundDestination' => $user->softphone_inbound_destination,\n 'softphoneHasVoiceCapability' => $softphoneHasVoiceCapability,\n 'softphoneNumber' => $user->getSoftPhoneNumber(),\n 'formattedSoftphoneNumber' => $user->getFormattedSoftphoneNumberAttribute(),\n 'email' => $user->getEmailAddress(),\n 'secondaryEmail' => $user->getSecondaryEmailAddress(),\n 'phone' => $user->phone,\n 'secondaryPhone' => $user->secondary_phone,\n 'callerId' => $user->getCallerId(),\n 'countryCode' => $user->getCountryCode(),\n 'timezone' => $user->getTimezone()->getName(),\n 'language' => $user->getLanguage(),\n 'locales' => $this->container->get(UserRepository::class)->getUserLocales($user),\n 'status' => $user->getStatus(),\n 'hash' => $user->generateHash(),\n 'registrationDate' => $user->created_at ? $user->created_at->toIso8601String() : null,\n 'notifyLiveCoaching' => $user->notify_live_coaching,\n 'activityLogReminder' => $user->activity_log_reminder,\n 'conferenceSidekickOpen' => $conferenceSidekickOpen,\n 'softphoneSidekickOpen' => $softphoneSidekickOpen,\n 'conferenceSidekickPopupOverridden' => $conferenceSidekickPopupOverridden,\n 'softphoneSidekickPopupOverridden' => $softphoneSidekickPopupOverridden,\n 'hasSidekickEnabled' => $hasSidekickEnabled,\n 'activityActionItems' => $user->activity_action_items,\n 'syncEmail' => $user->isSyncEmailEnabled(),\n 'syncConference' => $user->sync_conference,\n 'syncDialer' => $user->shouldSyncDialer(),\n 'needsToConfigurePhoneNumber' => $this->container\n ->get('onboarding_phone_decider')\n ->isOnboardable($user),\n 'shouldShowPhoneNumberField' => $this->container\n ->get('onboarding_phone_decider')\n ->shouldShowPhoneNumberField($user),\n UserSetting::DEAL_INSIGHTS_TIMELINE_PERIOD => $dealInsightsPeriod,\n 'countryByTimezone' => $dataFormatCountryCode,\n 'conferenceSlug' => $user->getConferenceSlug(),\n 'conferenceRecordExternalOrganizerPreference' =>\n $userService->isConferenceRecordExternalOrganizerPreferenceEnabled($user),\n 'hasGeneratedAiReports' => $this->getAutomatedReportsRepository()->countUserReports($user) > 0,\n 'sendEmailWhenExportLinkIsOpened' => $userService->canSendEmailWhenExportLinkIsOpened($user),\n ];\n\n if ($user->softphone_debug) {\n $attributes += [\n 'debugSoftphone' => $user->softphone_debug, // Needed?\n ];\n }\n }\n\n if ($user->getTeam()->getNotificationProvider() === Team::NOTIFICATION_PROVIDER_MSTEAMS) {\n $socialAccountMS = $user->getSocialAccount(Team::CALENDAR_PROVIDER_OFFICE);\n $state = $socialAccountMS !== null\n ? str_contains($socialAccountMS->auth_scope, MsTeams::SCOPE_CHAT_CREATE)\n : null;\n\n $attributes['integrations']['office'] = [\n 'displayName' => 'Microsoft Teams',\n 'apiName' => 'microsoft-teams',\n 'types' => ['notification'],\n 'state' => $state ? Provider::STATE_INSTALLED : Provider::STATE_NOT_INSTALLED,\n 'logo' => cdn('img/ms-teams-logo.svg'),\n 'installationStrategy' => 'oauth',\n ];\n }\n\n return $attributes;\n }\n\n public function includeTeam(User $user): Item\n {\n $team = $user->getTeam();\n\n return $this->item($team, $this->getTeamTransformer());\n }\n\n public function includeGroup(User $user): ?Item\n {\n $group = $user->getGroup();\n if ($group === null) {\n return null;\n }\n\n return $this->item($group, $this->getGroupTransformer());\n }\n\n public function includeJob(User $user): ?Item\n {\n $job = $user->getJobTitle();\n\n if (! $job instanceof JobTitle) {\n return null;\n }\n\n return $this->item($job, $this->getJobTitleTransformer());\n }\n\n public function includeRoles(User $user): Resource\\Collection\n {\n /** @var Collection<int, string> $roles */\n $roles = $user->roles()\n ->where('is_visible', true)\n ->pluck('name')\n ->toArray();\n\n return $this->collection($roles, $this->getRoleTransformer());\n }\n\n public function includePermissions(User $user): Resource\\Collection\n {\n $permissions = $user->allPermissions();\n\n return $this->collection($permissions, $this->getPermissionTransformer());\n }\n\n public function includeIntegrations(User $user): Item\n {\n return $this->item($user, $this->getIntegrationsTransformer());\n }\n\n private function getTeamTransformer(): TransformerAbstract\n {\n return $this->container->get(TeamTransformer::class);\n }\n\n private function getGroupTransformer(): GroupTransformer\n {\n return $this->container->get(GroupTransformer::class);\n }\n\n private function getIntegrationsTransformer(): IntegrationTransformer\n {\n return $this->container->get(IntegrationTransformer::class);\n }\n\n private function getPermissionTransformer(): PermissionTransformer\n {\n return $this->container->get(PermissionTransformer::class);\n }\n\n private function getRoleTransformer(): RoleTransformer\n {\n return $this->container->get(RoleTransformer::class);\n }\n\n private function getJobTitleTransformer(): JobTitleTransformer\n {\n return $this->container->get(JobTitleTransformer::class);\n }\n\n private function getSidekickService(): SidekickService\n {\n /** @var SidekickService */\n return $this->container->get(SidekickService::class);\n }\n\n private function getUserService(): UserService\n {\n /** @var UserService */\n return $this->container->get(UserService::class);\n }\n\n private function getAutomatedReportsRepository(): AutomatedReportsRepository\n {\n /** @var AutomatedReportsRepository */\n return $this->container->get(AutomatedReportsRepository::class);\n }\n}","depth":4,"value":"<?php\n\nnamespace Jiminny\\Http\\Transformers;\n\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\Sidekick\\SidekickService;\nuse Jiminny\\Exceptions\\ActivityProviderException;\nuse Jiminny\\Http\\Controllers\\Settings\\Users\\Utils\\UserSetting;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\JobTitle;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Notification\\Messengers\\MsTeams;\nuse Jiminny\\Services\\UserService;\nuse League\\Fractal\\Resource;\nuse League\\Fractal\\Resource\\Item;\nuse League\\Fractal\\TransformerAbstract;\n\nclass UserTransformer extends TransformerAbstract\n{\n protected array $availableIncludes = [\n 'team',\n 'group',\n 'job',\n 'roles',\n 'permissions',\n ];\n\n private Container $container;\n\n private bool $withSelfVisibility = false;\n\n public function __construct(?Container $container = null)\n {\n $this->container = $container ?? app();\n }\n\n public function withSelfVisibility(): self\n {\n $this->withSelfVisibility = true;\n\n return $this;\n }\n\n /**\n * @throws ActivityProviderException\n *\n * @return array<string, mixed>\n */\n public function transform(User $user): array\n {\n $attributes = [\n 'id' => $user->getUuid(),\n 'name' => $user->getName(),\n 'firstName' => $user->getFirstName(),\n 'photoUrl' => $user->getPhotoUrl(),\n 'conferenceRecordPreference' => $user->checkConferenceRecordPreference(),\n 'conferenceRecordInternalPreference' => $user->checkConferenceRecordInternalPreference(),\n // DO NOT USE User::isCrmRequired as it is not hydrated when fetched from ES!\n 'crmRequired' => $user->crm_required,\n 'slackFollowUp' => $user->slack_follow_up,\n ];\n\n // DO NOT USE User::getId as it is not hydrated when fetched from ES!\n if ($this->withSelfVisibility || (auth()->check() && auth()->user()->id === $user->id)) {\n $softphoneHasVoiceCapability = $user->hasSoftphoneNumberCapabilities()\n && $user->getSoftphoneNumberCapabilities()->hasVoiceCapability()\n ;\n\n $conferenceSidekickOpen = $user->getConferenceSidekickOpen();\n $softphoneSidekickOpen = $user->getSoftphoneSidekickOpen();\n $conferenceSidekickPopupOverridden = false;\n $softphoneSidekickPopupOverridden = false;\n $hasSidekickEnabled = true;\n\n if ($user->getTeam()->hasFeature(FeatureEnum::SIDEKICK_SETTINGS)) {\n $sidekickService = $this->getSidekickService();\n\n $sidekickData = $sidekickService->getSidekickSettingsForUser($user);\n\n $conferenceSidekickOpen = $sidekickData['conferenceSettings'];\n $softphoneSidekickOpen = $sidekickData['softphoneSettings'];\n $conferenceSidekickPopupOverridden = $sidekickData['conferenceSidekickPopupOverridden'];\n $softphoneSidekickPopupOverridden = $sidekickData['softphoneSidekickPopupOverridden'];\n $hasSidekickEnabled = $sidekickData['sidekickEnabled'];\n }\n\n $userService = $this->getUserService();\n $dealInsightsPeriod = $userService->getDealInsightTimelinePeriod($user);\n $dataFormatCountryCode = $userService->getDateTimeCountryCode($user);\n\n // Attributes for the user only.\n $attributes += [\n 'conferenceJoinReminder' => $user->conference_join_reminder,\n 'softphoneInboundRecordPreference' => $user->checkSoftphoneInboundRecordPreference(),\n 'softphoneOutboundRecordPreference' => $user->checkSoftphoneOutboundRecordPreference(),\n 'softphoneInboundDestination' => $user->softphone_inbound_destination,\n 'softphoneHasVoiceCapability' => $softphoneHasVoiceCapability,\n 'softphoneNumber' => $user->getSoftPhoneNumber(),\n 'formattedSoftphoneNumber' => $user->getFormattedSoftphoneNumberAttribute(),\n 'email' => $user->getEmailAddress(),\n 'secondaryEmail' => $user->getSecondaryEmailAddress(),\n 'phone' => $user->phone,\n 'secondaryPhone' => $user->secondary_phone,\n 'callerId' => $user->getCallerId(),\n 'countryCode' => $user->getCountryCode(),\n 'timezone' => $user->getTimezone()->getName(),\n 'language' => $user->getLanguage(),\n 'locales' => $this->container->get(UserRepository::class)->getUserLocales($user),\n 'status' => $user->getStatus(),\n 'hash' => $user->generateHash(),\n 'registrationDate' => $user->created_at ? $user->created_at->toIso8601String() : null,\n 'notifyLiveCoaching' => $user->notify_live_coaching,\n 'activityLogReminder' => $user->activity_log_reminder,\n 'conferenceSidekickOpen' => $conferenceSidekickOpen,\n 'softphoneSidekickOpen' => $softphoneSidekickOpen,\n 'conferenceSidekickPopupOverridden' => $conferenceSidekickPopupOverridden,\n 'softphoneSidekickPopupOverridden' => $softphoneSidekickPopupOverridden,\n 'hasSidekickEnabled' => $hasSidekickEnabled,\n 'activityActionItems' => $user->activity_action_items,\n 'syncEmail' => $user->isSyncEmailEnabled(),\n 'syncConference' => $user->sync_conference,\n 'syncDialer' => $user->shouldSyncDialer(),\n 'needsToConfigurePhoneNumber' => $this->container\n ->get('onboarding_phone_decider')\n ->isOnboardable($user),\n 'shouldShowPhoneNumberField' => $this->container\n ->get('onboarding_phone_decider')\n ->shouldShowPhoneNumberField($user),\n UserSetting::DEAL_INSIGHTS_TIMELINE_PERIOD => $dealInsightsPeriod,\n 'countryByTimezone' => $dataFormatCountryCode,\n 'conferenceSlug' => $user->getConferenceSlug(),\n 'conferenceRecordExternalOrganizerPreference' =>\n $userService->isConferenceRecordExternalOrganizerPreferenceEnabled($user),\n 'hasGeneratedAiReports' => $this->getAutomatedReportsRepository()->countUserReports($user) > 0,\n 'sendEmailWhenExportLinkIsOpened' => $userService->canSendEmailWhenExportLinkIsOpened($user),\n ];\n\n if ($user->softphone_debug) {\n $attributes += [\n 'debugSoftphone' => $user->softphone_debug, // Needed?\n ];\n }\n }\n\n if ($user->getTeam()->getNotificationProvider() === Team::NOTIFICATION_PROVIDER_MSTEAMS) {\n $socialAccountMS = $user->getSocialAccount(Team::CALENDAR_PROVIDER_OFFICE);\n $state = $socialAccountMS !== null\n ? str_contains($socialAccountMS->auth_scope, MsTeams::SCOPE_CHAT_CREATE)\n : null;\n\n $attributes['integrations']['office'] = [\n 'displayName' => 'Microsoft Teams',\n 'apiName' => 'microsoft-teams',\n 'types' => ['notification'],\n 'state' => $state ? Provider::STATE_INSTALLED : Provider::STATE_NOT_INSTALLED,\n 'logo' => cdn('img/ms-teams-logo.svg'),\n 'installationStrategy' => 'oauth',\n ];\n }\n\n return $attributes;\n }\n\n public function includeTeam(User $user): Item\n {\n $team = $user->getTeam();\n\n return $this->item($team, $this->getTeamTransformer());\n }\n\n public function includeGroup(User $user): ?Item\n {\n $group = $user->getGroup();\n if ($group === null) {\n return null;\n }\n\n return $this->item($group, $this->getGroupTransformer());\n }\n\n public function includeJob(User $user): ?Item\n {\n $job = $user->getJobTitle();\n\n if (! $job instanceof JobTitle) {\n return null;\n }\n\n return $this->item($job, $this->getJobTitleTransformer());\n }\n\n public function includeRoles(User $user): Resource\\Collection\n {\n /** @var Collection<int, string> $roles */\n $roles = $user->roles()\n ->where('is_visible', true)\n ->pluck('name')\n ->toArray();\n\n return $this->collection($roles, $this->getRoleTransformer());\n }\n\n public function includePermissions(User $user): Resource\\Collection\n {\n $permissions = $user->allPermissions();\n\n return $this->collection($permissions, $this->getPermissionTransformer());\n }\n\n public function includeIntegrations(User $user): Item\n {\n return $this->item($user, $this->getIntegrationsTransformer());\n }\n\n private function getTeamTransformer(): TransformerAbstract\n {\n return $this->container->get(TeamTransformer::class);\n }\n\n private function getGroupTransformer(): GroupTransformer\n {\n return $this->container->get(GroupTransformer::class);\n }\n\n private function getIntegrationsTransformer(): IntegrationTransformer\n {\n return $this->container->get(IntegrationTransformer::class);\n }\n\n private function getPermissionTransformer(): PermissionTransformer\n {\n return $this->container->get(PermissionTransformer::class);\n }\n\n private function getRoleTransformer(): RoleTransformer\n {\n return $this->container->get(RoleTransformer::class);\n }\n\n private function getJobTitleTransformer(): JobTitleTransformer\n {\n return $this->container->get(JobTitleTransformer::class);\n }\n\n private function getSidekickService(): SidekickService\n {\n /** @var SidekickService */\n return $this->container->get(SidekickService::class);\n }\n\n private function getUserService(): UserService\n {\n /** @var UserService */\n return $this->container->get(UserService::class);\n }\n\n private function getAutomatedReportsRepository(): AutomatedReportsRepository\n {\n /** @var AutomatedReportsRepository */\n return $this->container->get(AutomatedReportsRepository::class);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"36","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\DealInsights;\n\nuse Doctrine\\DBAL\\Connection;\nuse Generator;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Facades\\DB;\nuse Jiminny\\Component\\DealInsights\\Forecast\\DealData;\nuse Jiminny\\Component\\DealInsights\\Forecast\\DealsFilter;\nuse Jiminny\\Component\\DealInsights\\QueryBuilder\\QueryBuilder;\nuse Jiminny\\Component\\DealInsights\\QueryBuilder\\Visitor\\QueryBuilderVisitorInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Models;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\Utils\\UrlGeneratorInterface;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Database\\Eloquent;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\n\nclass DealsRepository implements DealsRepositoryInterface\n{\n private Connection $connection;\n\n private ProviderRegistry $providerRegistry;\n\n /**\n * @var QueryBuilderVisitorInterface[]\n */\n private array $visitors = [];\n\n /**\n * @param QueryBuilderVisitorInterface[] $visitors\n */\n public function __construct(Connection $connection, ProviderRegistry $crmProviderRegistry, array $visitors = [])\n {\n $this->connection = $connection;\n $this->providerRegistry = $crmProviderRegistry;\n\n foreach ($visitors as $visitor) {\n $this->visitors[$visitor->getIdentifier()] = $visitor;\n }\n }\n\n public function getDeals(CriteriaInterface $criteria): array\n {\n $context = $criteria->getContext();\n $team = $context->getTeam();\n $crmService = $this->getCrmService($team);\n\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);\n $qb = $this->getSearchSelectAndWhereClauses($qb);\n\n $this->visit($qb, $criteria);\n\n return $this->execute($team, $crmService, $qb);\n }\n\n public function getDeal(Team $team, int $id): array\n {\n $crmService = $this->getCrmService($team);\n\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);\n $qb = $this->getSearchSelectAndWhereClauses($qb);\n $qb->andWhere('opp.id = :id')->setParameter('id', $id);\n\n return $this->execute($team, $crmService, $qb);\n }\n\n public function getCrmFieldData(array $crmFields, int $crmId, array $opportunityIds = [])\n {\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('f.id', 'f.crm_provider_id AS field_name', 'f.label', 'fd.object_id AS dealId', 'fd.value')\n ->from('crm_fields', 'f')\n ->join('f', 'crm_field_data', 'fd', 'fd.crm_field_id = f.id')\n ->where('f.crm_configuration_id = :crm')\n ->andWhere('f.object_type = :type')\n ->andWhere('fd.object_id IN (' . implode(',', $opportunityIds) . ')')\n ->orderBy('fd.object_id', 'ASC')\n ->addOrderBy('fd.updated_at', 'ASC')\n\n ->setParameter('type', Field::OBJECT_OPPORTUNITY)\n ->setParameter('crm', $crmId)\n ;\n\n if (! empty($crmFields)) {\n $fields = array_map(fn ($value): string => '\"' . $value . '\"', $crmFields);\n $qb->andWhere('f.crm_provider_id IN (' . implode(',', $fields) . ')');\n }\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n public function getTotalsInDefaultCurrency(CriteriaInterface $criteria): array\n {\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);\n\n $qb\n ->select('SUM(opp.value) as total')\n ->addSelect('count(*) as `count`')\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'))\n ;\n\n $this->visit($qb, $criteria);\n\n return $qb->executeQuery()->fetchAssociative();\n }\n\n public function getTotals(CriteriaInterface $criteria, string $defaultCurrency): array\n {\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);\n\n $qb\n ->select('COALESCE(opp.currency_code, \"' . $defaultCurrency . '\") AS currency')\n ->addSelect('SUM(opp.value) as total')\n ->addSelect('count(*) as `count`')\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'))\n ->groupBy('currency')\n ;\n\n $this->visit($qb, $criteria);\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n public function getDealActivities(CriteriaInterface $criteria): array\n {\n $qb = Activity::with(['participants', 'user'])\n ->where('opportunity_id', $criteria->getOpportunityId())\n ->whereDate('actual_start_time', '>=', $criteria->getPeriod()->getStartDate())\n ->whereDate('actual_start_time', '<=', $criteria->getPeriod()->getEndDate())\n ->orderBy($criteria->getSortBy(), $criteria->getSortDirection())\n ;\n\n // Should we filter activities by criteria? It's intended to filter deals.\n\n return $qb->get()->all();\n }\n\n public function getStages(CriteriaInterface $criteria): array\n {\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('id', 'label', 'sequence')\n ->from('stages', 's')\n ->where('crm_configuration_id = :crm_configuration_id')\n ->andWhere('type = :type')\n ->orderBy('sequence', 'ASC')\n\n ->setParameter('crm_configuration_id', $criteria->getContext()->getTeam()->getCrmConfiguration()->getId())\n ->setParameter('type', Stage::TYPE_OPPORTUNITY);\n\n $result = [];\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $result[$row['id']] = [\n 'label' => $row['label'],\n 'sequence' => $row['sequence'],\n ];\n }\n\n return $result;\n }\n\n public function getConfigurationStages(Configuration $configuration): Collection\n {\n return $configuration\n ->stages()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get();\n }\n\n public function getPipelineData(Configuration $crm): array\n {\n $qb = new QueryBuilder($this->connection);\n $provider = $crm->provider;\n\n $qb\n ->select('s.label', 's.crm_provider_id', 's.sequence', 'bps.business_process_id AS pipeline_id')\n ->from('stages', 's')\n ->join('s', 'business_process_stages', 'bps', 's.id=bps.stage_id')\n ->where('s.crm_configuration_id = :crm_configuration_id')\n ->andWhere('s.type = :type')\n ->orderBy('bps.business_process_id', 'ASC')\n ->addOrderBy('s.sequence', 'ASC')\n\n ->setParameter('crm_configuration_id', $crm->id)\n ->setParameter('type', Stage::TYPE_OPPORTUNITY)\n ;\n\n $result = [];\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $value = $provider === Configuration::PROVIDER_SALESFORCE ? $row['label'] : $row['crm_provider_id'];\n $result[$row['pipeline_id']][] = [\n 'value' => $value,\n 'label' => $row['label'],\n 'sequence' => $row['sequence'],\n ];\n }\n\n return $result;\n }\n\n private function createQueryBuilder(string $realm): QueryBuilder\n {\n return (new QueryBuilder($this->connection))\n ->setRealm($realm)\n ->from('opportunities', 'opp')\n ->leftJoin('opp', 'record_types', 'rt', 'opp.record_type_id = rt.id')\n ->leftJoin('opp', 'users', 'usr', 'opp.user_id = usr.id')\n ->leftJoin('opp', 'accounts', 'acc', 'opp.account_id = acc.id')\n ;\n }\n\n /**\n * Applies all applicable visitors and returns the IDs of the executed ones\n *\n * @return string[]\n */\n private function visit(QueryBuilder $queryBuilder, CriteriaInterface $criteria): array\n {\n $queryVisitors = [];\n\n foreach ($this->visitors as $visitor) {\n if ($visitor->isSatisfiedBy($criteria, $queryBuilder->getRealm())) {\n $visitor->visit($queryBuilder, $criteria);\n\n $queryVisitors[] = $visitor->getIdentifier();\n }\n }\n\n return $queryVisitors;\n }\n\n private function hydrateStages(array $deals): array\n {\n foreach ($this->fetchStages(array_keys($deals)) as $stage) {\n $oppId = (int) $stage['opportunity_id'];\n\n if (! isset($deals[$oppId])) {\n continue; // or throw??!\n }\n\n $deals[$oppId]['stages'][] = [\n 'id' => $stage['stage_id'],\n 'name' => $stage['label'],\n 'enteredAt' => $stage['created_at'],\n ];\n }\n\n return $deals;\n }\n\n /**\n * @param int[] $dealIds\n */\n private function fetchStages(array $dealIds): array\n {\n if (empty($dealIds)) {\n return [];\n }\n\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('os.opportunity_id', 's.id AS stage_id', 's.label', 's.created_at')\n ->from('opportunity_stages', 'os')\n ->leftJoin('os', 'stages', 's', 'os.stage_id=s.id')\n ->where($qb->expr()->in('os.opportunity_id', $dealIds))\n ->orderBy('os.opportunity_id', 'ASC')\n ->addOrderBy('s.created_at', 'ASC')\n ;\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n private function execute(Team $team, ServiceInterface $crmService, QueryBuilder $qb): array\n {\n $result = [];\n\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $data = [\n 'uuid' => RequiresUUID::toNormal($row['uuid']),\n 'name' => $row['name'],\n 'url' => $crmService->generateProviderUrl($row['opp_provider_id'], 'opportunity'),\n 'account' => [\n 'name' => $row['acc_name'],\n 'url' => $crmService->generateProviderUrl(\n providerId: $row['acc_provider_id'],\n objectType: $row['acc_is_internal'] ? 'internal-account' : 'account'\n ),\n ],\n 'owner' => null,\n 'rawValue' => [\n 'amount' => (float) $row['value'],\n 'currency' => $row['currency_code'],\n ],\n 'value' => formatOpportunityValue((float) $row['value'], $row['currency_code']),\n 'openDate' => $row['remotely_created_at'] ?? null,\n 'closeDate' => $row['close_date'] ?? null,\n 'stages' => [],\n 'currentPipelineId' => $row['pipeline_id'],\n 'currentStage' => [\n 'id' => $row['stage_id'],\n 'enteredAt' => $row['stage_updated_at'],\n ],\n 'currentStageUpdatedAt' => $row['stage_updated_at'],\n 'isClosed' => (bool) $row['is_closed'],\n 'isWon' => (bool) $row['is_won'],\n ];\n\n if (isset($row['owner_uuid'])) {\n $data['owner'] = [\n 'uuid' => RequiresUUID::toNormal($row['owner_uuid']),\n 'name' => $row['owner_name'],\n 'photoUrl' => $row['owner_photo'] === null\n ? null\n : client_cdn($row['owner_photo'], $team),\n 'id' => $row['owner_id'],\n 'job' => $row['owner_job'],\n ];\n }\n\n $result[(int) $row['opp_id']] = $data;\n }\n\n return $this->hydrateStages($result);\n }\n\n private function getSearchSelectAndWhereClauses(QueryBuilder $queryBuilder): QueryBuilder\n {\n $qb = clone $queryBuilder;\n $qb->leftJoin('usr', 'job_titles', 'jt', 'usr.job_title_id = jt.id');\n\n $qb\n ->select(...[\n 'opp.id as opp_id',\n 'opp.uuid',\n 'opp.name',\n 'opp.value',\n 'opp.currency_code',\n 'opp.close_date',\n 'opp.remotely_created_at',\n 'opp.is_closed',\n 'opp.is_won',\n ])\n ->addSelect(...[\n 'usr.uuid as owner_uuid',\n 'usr.name AS owner_name',\n 'usr.photo_path as owner_photo',\n 'usr.id AS owner_id',\n 'jt.name as owner_job',\n ])\n ->addSelect('opp.stage_id', 'opp.stage_updated_at')\n ->addSelect(...[\n 'acc.name AS acc_name',\n 'acc.is_internal as acc_is_internal',\n 'opp.stage_updated_at',\n 'acc.crm_provider_id AS acc_provider_id',\n 'opp.crm_provider_id AS opp_provider_id',\n ])\n ->addSelect('rt.business_process_id AS pipeline_id')\n\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not display deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'));\n\n return $qb;\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws SocialAccountTokenInvalidException\n */\n private function getCrmService(Team $team): ServiceInterface\n {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n $crmService->setConfiguration($team->crm);\n if ($crmService instanceof UrlGeneratorInterface) {\n $crmService->setCrmUrlGenerator($team->crm);\n }\n\n return $crmService;\n }\n\n /**\n *\n * @return Generator<DealData>\n */\n public function getForecastData(DealsFilter $filter): Generator\n {\n $opportunities = DB::query()\n ->select([\n 'o.value',\n 'o.close_date',\n 'o.currency_code',\n 'o.is_won',\n 'o.is_closed',\n 'o.probability',\n 'o.forecast_category',\n ])\n ->from('opportunities', 'o')\n ->join('users', 'users.id', '=', 'o.user_id')\n ->join('groups', 'groups.id', '=', 'users.group_id')\n ->where('users.team_id', $filter->getTeam()->getId())\n ->where('o.close_date', '>=', $filter->getStartDate())\n ->where('o.close_date', '<=', $filter->getEndDate())\n ->where('o.currency_code', $filter->getCurrency())\n ->where('o.deleted_at', '=', null)\n ;\n\n $userUuidList = $filter->getUserUuidList();\n if (! empty($userUuidList)) {\n $userUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $userUuidList);\n\n $opportunities->whereIn('users.uuid', $userUuidList);\n }\n\n $groupUuidList = $filter->getGroupUuidList();\n if (! empty($groupUuidList)) {\n $groupUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $groupUuidList);\n\n $opportunities->whereIn('groups.uuid', $groupUuidList);\n }\n\n foreach ($opportunities->cursor() as $row) {\n yield new DealData(\n (float) $row->value,\n $row->close_date,\n ! empty($row->is_won),\n ! empty($row->is_closed),\n $row->probability ?: 0,\n $row->forecast_category ?: '',\n );\n }\n }\n\n public function getUserOpportunitySubscriptions(User $user, array $opportunityIds): Collection\n {\n return $user->subscriptionSets()\n ->where(static function (Eloquent\\Builder $query): void {\n $query\n ->whereNull('expired_at')\n ->orWhere('expired_at', '>=', now());\n })\n ->join('activity_subscriptions', function (Builder $join) use ($opportunityIds) {\n $join\n ->on('subscription_set_id', '=', 'activity_subscription_sets.id');\n $join\n ->where('followable_type', Models\\Activity\\Subscription::FOLLOWABLE_TYPE_OPPORTUNITY)\n ->whereIn('followable_id', $opportunityIds);\n })\n ->pluck('followable_id');\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\DealInsights;\n\nuse Doctrine\\DBAL\\Connection;\nuse Generator;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Facades\\DB;\nuse Jiminny\\Component\\DealInsights\\Forecast\\DealData;\nuse Jiminny\\Component\\DealInsights\\Forecast\\DealsFilter;\nuse Jiminny\\Component\\DealInsights\\QueryBuilder\\QueryBuilder;\nuse Jiminny\\Component\\DealInsights\\QueryBuilder\\Visitor\\QueryBuilderVisitorInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Models;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\Utils\\UrlGeneratorInterface;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Database\\Eloquent;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\n\nclass DealsRepository implements DealsRepositoryInterface\n{\n private Connection $connection;\n\n private ProviderRegistry $providerRegistry;\n\n /**\n * @var QueryBuilderVisitorInterface[]\n */\n private array $visitors = [];\n\n /**\n * @param QueryBuilderVisitorInterface[] $visitors\n */\n public function __construct(Connection $connection, ProviderRegistry $crmProviderRegistry, array $visitors = [])\n {\n $this->connection = $connection;\n $this->providerRegistry = $crmProviderRegistry;\n\n foreach ($visitors as $visitor) {\n $this->visitors[$visitor->getIdentifier()] = $visitor;\n }\n }\n\n public function getDeals(CriteriaInterface $criteria): array\n {\n $context = $criteria->getContext();\n $team = $context->getTeam();\n $crmService = $this->getCrmService($team);\n\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);\n $qb = $this->getSearchSelectAndWhereClauses($qb);\n\n $this->visit($qb, $criteria);\n\n return $this->execute($team, $crmService, $qb);\n }\n\n public function getDeal(Team $team, int $id): array\n {\n $crmService = $this->getCrmService($team);\n\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);\n $qb = $this->getSearchSelectAndWhereClauses($qb);\n $qb->andWhere('opp.id = :id')->setParameter('id', $id);\n\n return $this->execute($team, $crmService, $qb);\n }\n\n public function getCrmFieldData(array $crmFields, int $crmId, array $opportunityIds = [])\n {\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('f.id', 'f.crm_provider_id AS field_name', 'f.label', 'fd.object_id AS dealId', 'fd.value')\n ->from('crm_fields', 'f')\n ->join('f', 'crm_field_data', 'fd', 'fd.crm_field_id = f.id')\n ->where('f.crm_configuration_id = :crm')\n ->andWhere('f.object_type = :type')\n ->andWhere('fd.object_id IN (' . implode(',', $opportunityIds) . ')')\n ->orderBy('fd.object_id', 'ASC')\n ->addOrderBy('fd.updated_at', 'ASC')\n\n ->setParameter('type', Field::OBJECT_OPPORTUNITY)\n ->setParameter('crm', $crmId)\n ;\n\n if (! empty($crmFields)) {\n $fields = array_map(fn ($value): string => '\"' . $value . '\"', $crmFields);\n $qb->andWhere('f.crm_provider_id IN (' . implode(',', $fields) . ')');\n }\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n public function getTotalsInDefaultCurrency(CriteriaInterface $criteria): array\n {\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);\n\n $qb\n ->select('SUM(opp.value) as total')\n ->addSelect('count(*) as `count`')\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'))\n ;\n\n $this->visit($qb, $criteria);\n\n return $qb->executeQuery()->fetchAssociative();\n }\n\n public function getTotals(CriteriaInterface $criteria, string $defaultCurrency): array\n {\n $qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);\n\n $qb\n ->select('COALESCE(opp.currency_code, \"' . $defaultCurrency . '\") AS currency')\n ->addSelect('SUM(opp.value) as total')\n ->addSelect('count(*) as `count`')\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'))\n ->groupBy('currency')\n ;\n\n $this->visit($qb, $criteria);\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n public function getDealActivities(CriteriaInterface $criteria): array\n {\n $qb = Activity::with(['participants', 'user'])\n ->where('opportunity_id', $criteria->getOpportunityId())\n ->whereDate('actual_start_time', '>=', $criteria->getPeriod()->getStartDate())\n ->whereDate('actual_start_time', '<=', $criteria->getPeriod()->getEndDate())\n ->orderBy($criteria->getSortBy(), $criteria->getSortDirection())\n ;\n\n // Should we filter activities by criteria? It's intended to filter deals.\n\n return $qb->get()->all();\n }\n\n public function getStages(CriteriaInterface $criteria): array\n {\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('id', 'label', 'sequence')\n ->from('stages', 's')\n ->where('crm_configuration_id = :crm_configuration_id')\n ->andWhere('type = :type')\n ->orderBy('sequence', 'ASC')\n\n ->setParameter('crm_configuration_id', $criteria->getContext()->getTeam()->getCrmConfiguration()->getId())\n ->setParameter('type', Stage::TYPE_OPPORTUNITY);\n\n $result = [];\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $result[$row['id']] = [\n 'label' => $row['label'],\n 'sequence' => $row['sequence'],\n ];\n }\n\n return $result;\n }\n\n public function getConfigurationStages(Configuration $configuration): Collection\n {\n return $configuration\n ->stages()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get();\n }\n\n public function getPipelineData(Configuration $crm): array\n {\n $qb = new QueryBuilder($this->connection);\n $provider = $crm->provider;\n\n $qb\n ->select('s.label', 's.crm_provider_id', 's.sequence', 'bps.business_process_id AS pipeline_id')\n ->from('stages', 's')\n ->join('s', 'business_process_stages', 'bps', 's.id=bps.stage_id')\n ->where('s.crm_configuration_id = :crm_configuration_id')\n ->andWhere('s.type = :type')\n ->orderBy('bps.business_process_id', 'ASC')\n ->addOrderBy('s.sequence', 'ASC')\n\n ->setParameter('crm_configuration_id', $crm->id)\n ->setParameter('type', Stage::TYPE_OPPORTUNITY)\n ;\n\n $result = [];\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $value = $provider === Configuration::PROVIDER_SALESFORCE ? $row['label'] : $row['crm_provider_id'];\n $result[$row['pipeline_id']][] = [\n 'value' => $value,\n 'label' => $row['label'],\n 'sequence' => $row['sequence'],\n ];\n }\n\n return $result;\n }\n\n private function createQueryBuilder(string $realm): QueryBuilder\n {\n return (new QueryBuilder($this->connection))\n ->setRealm($realm)\n ->from('opportunities', 'opp')\n ->leftJoin('opp', 'record_types', 'rt', 'opp.record_type_id = rt.id')\n ->leftJoin('opp', 'users', 'usr', 'opp.user_id = usr.id')\n ->leftJoin('opp', 'accounts', 'acc', 'opp.account_id = acc.id')\n ;\n }\n\n /**\n * Applies all applicable visitors and returns the IDs of the executed ones\n *\n * @return string[]\n */\n private function visit(QueryBuilder $queryBuilder, CriteriaInterface $criteria): array\n {\n $queryVisitors = [];\n\n foreach ($this->visitors as $visitor) {\n if ($visitor->isSatisfiedBy($criteria, $queryBuilder->getRealm())) {\n $visitor->visit($queryBuilder, $criteria);\n\n $queryVisitors[] = $visitor->getIdentifier();\n }\n }\n\n return $queryVisitors;\n }\n\n private function hydrateStages(array $deals): array\n {\n foreach ($this->fetchStages(array_keys($deals)) as $stage) {\n $oppId = (int) $stage['opportunity_id'];\n\n if (! isset($deals[$oppId])) {\n continue; // or throw??!\n }\n\n $deals[$oppId]['stages'][] = [\n 'id' => $stage['stage_id'],\n 'name' => $stage['label'],\n 'enteredAt' => $stage['created_at'],\n ];\n }\n\n return $deals;\n }\n\n /**\n * @param int[] $dealIds\n */\n private function fetchStages(array $dealIds): array\n {\n if (empty($dealIds)) {\n return [];\n }\n\n $qb = new QueryBuilder($this->connection);\n\n $qb\n ->select('os.opportunity_id', 's.id AS stage_id', 's.label', 's.created_at')\n ->from('opportunity_stages', 'os')\n ->leftJoin('os', 'stages', 's', 'os.stage_id=s.id')\n ->where($qb->expr()->in('os.opportunity_id', $dealIds))\n ->orderBy('os.opportunity_id', 'ASC')\n ->addOrderBy('s.created_at', 'ASC')\n ;\n\n return $qb->executeQuery()->fetchAllAssociative();\n }\n\n private function execute(Team $team, ServiceInterface $crmService, QueryBuilder $qb): array\n {\n $result = [];\n\n foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {\n $data = [\n 'uuid' => RequiresUUID::toNormal($row['uuid']),\n 'name' => $row['name'],\n 'url' => $crmService->generateProviderUrl($row['opp_provider_id'], 'opportunity'),\n 'account' => [\n 'name' => $row['acc_name'],\n 'url' => $crmService->generateProviderUrl(\n providerId: $row['acc_provider_id'],\n objectType: $row['acc_is_internal'] ? 'internal-account' : 'account'\n ),\n ],\n 'owner' => null,\n 'rawValue' => [\n 'amount' => (float) $row['value'],\n 'currency' => $row['currency_code'],\n ],\n 'value' => formatOpportunityValue((float) $row['value'], $row['currency_code']),\n 'openDate' => $row['remotely_created_at'] ?? null,\n 'closeDate' => $row['close_date'] ?? null,\n 'stages' => [],\n 'currentPipelineId' => $row['pipeline_id'],\n 'currentStage' => [\n 'id' => $row['stage_id'],\n 'enteredAt' => $row['stage_updated_at'],\n ],\n 'currentStageUpdatedAt' => $row['stage_updated_at'],\n 'isClosed' => (bool) $row['is_closed'],\n 'isWon' => (bool) $row['is_won'],\n ];\n\n if (isset($row['owner_uuid'])) {\n $data['owner'] = [\n 'uuid' => RequiresUUID::toNormal($row['owner_uuid']),\n 'name' => $row['owner_name'],\n 'photoUrl' => $row['owner_photo'] === null\n ? null\n : client_cdn($row['owner_photo'], $team),\n 'id' => $row['owner_id'],\n 'job' => $row['owner_job'],\n ];\n }\n\n $result[(int) $row['opp_id']] = $data;\n }\n\n return $this->hydrateStages($result);\n }\n\n private function getSearchSelectAndWhereClauses(QueryBuilder $queryBuilder): QueryBuilder\n {\n $qb = clone $queryBuilder;\n $qb->leftJoin('usr', 'job_titles', 'jt', 'usr.job_title_id = jt.id');\n\n $qb\n ->select(...[\n 'opp.id as opp_id',\n 'opp.uuid',\n 'opp.name',\n 'opp.value',\n 'opp.currency_code',\n 'opp.close_date',\n 'opp.remotely_created_at',\n 'opp.is_closed',\n 'opp.is_won',\n ])\n ->addSelect(...[\n 'usr.uuid as owner_uuid',\n 'usr.name AS owner_name',\n 'usr.photo_path as owner_photo',\n 'usr.id AS owner_id',\n 'jt.name as owner_job',\n ])\n ->addSelect('opp.stage_id', 'opp.stage_updated_at')\n ->addSelect(...[\n 'acc.name AS acc_name',\n 'acc.is_internal as acc_is_internal',\n 'opp.stage_updated_at',\n 'acc.crm_provider_id AS acc_provider_id',\n 'opp.crm_provider_id AS opp_provider_id',\n ])\n ->addSelect('rt.business_process_id AS pipeline_id')\n\n ->where($qb->expr()->isNotNull('opp.user_id')) // we should not display deals owned by external users\n ->andWhere($qb->expr()->isNull('opp.deleted_at'));\n\n return $qb;\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws SocialAccountTokenInvalidException\n */\n private function getCrmService(Team $team): ServiceInterface\n {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n $crmService->setConfiguration($team->crm);\n if ($crmService instanceof UrlGeneratorInterface) {\n $crmService->setCrmUrlGenerator($team->crm);\n }\n\n return $crmService;\n }\n\n /**\n *\n * @return Generator<DealData>\n */\n public function getForecastData(DealsFilter $filter): Generator\n {\n $opportunities = DB::query()\n ->select([\n 'o.value',\n 'o.close_date',\n 'o.currency_code',\n 'o.is_won',\n 'o.is_closed',\n 'o.probability',\n 'o.forecast_category',\n ])\n ->from('opportunities', 'o')\n ->join('users', 'users.id', '=', 'o.user_id')\n ->join('groups', 'groups.id', '=', 'users.group_id')\n ->where('users.team_id', $filter->getTeam()->getId())\n ->where('o.close_date', '>=', $filter->getStartDate())\n ->where('o.close_date', '<=', $filter->getEndDate())\n ->where('o.currency_code', $filter->getCurrency())\n ->where('o.deleted_at', '=', null)\n ;\n\n $userUuidList = $filter->getUserUuidList();\n if (! empty($userUuidList)) {\n $userUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $userUuidList);\n\n $opportunities->whereIn('users.uuid', $userUuidList);\n }\n\n $groupUuidList = $filter->getGroupUuidList();\n if (! empty($groupUuidList)) {\n $groupUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $groupUuidList);\n\n $opportunities->whereIn('groups.uuid', $groupUuidList);\n }\n\n foreach ($opportunities->cursor() as $row) {\n yield new DealData(\n (float) $row->value,\n $row->close_date,\n ! empty($row->is_won),\n ! empty($row->is_closed),\n $row->probability ?: 0,\n $row->forecast_category ?: '',\n );\n }\n }\n\n public function getUserOpportunitySubscriptions(User $user, array $opportunityIds): Collection\n {\n return $user->subscriptionSets()\n ->where(static function (Eloquent\\Builder $query): void {\n $query\n ->whereNull('expired_at')\n ->orWhere('expired_at', '>=', now());\n })\n ->join('activity_subscriptions', function (Builder $join) use ($opportunityIds) {\n $join\n ->on('subscription_set_id', '=', 'activity_subscription_sets.id');\n $join\n ->where('followable_type', Models\\Activity\\Subscription::FOLLOWABLE_TYPE_OPPORTUNITY)\n ->whereIn('followable_id', $opportunityIds);\n })\n ->pluck('followable_id');\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAggregator.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAggregatorInterface.php, interface","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"DatabaseActivities.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"DatasourceInterface.php, interface","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"RelatedActivity.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"RelatedActivityInterface.php, interface","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"Commands","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Comments","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Forecast","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Jobs","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"QueryBuilder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Services","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"ClosingPeriodOptionDecorator.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"CreatedPeriodOptionDecorator.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Criteria.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"CriteriaInterface.php, interface","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"CriteriaNormalizer.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"CrmService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"CrmServiceInterface.php, interface","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"DealContactService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"DealInsightsCriteriaBuilder.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"DealService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"DealServiceInterface.php, interface","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"DealsRepository.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"DealsRepositoryInterface.php, interface","depth":10}]...
|
-5380076283229952570
|
8406683239789562236
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20157-AJ-report-not-se Project: faVsco.js, menu
JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
13
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Http\Transformers;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Collection;
use Jiminny\Component\Sidekick\SidekickService;
use Jiminny\Exceptions\ActivityProviderException;
use Jiminny\Http\Controllers\Settings\Users\Utils\UserSetting;
use Jiminny\Models\Activity\Provider;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\JobTitle;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Notification\Messengers\MsTeams;
use Jiminny\Services\UserService;
use League\Fractal\Resource;
use League\Fractal\Resource\Item;
use League\Fractal\TransformerAbstract;
class UserTransformer extends TransformerAbstract
{
protected array $availableIncludes = [
'team',
'group',
'job',
'roles',
'permissions',
];
private Container $container;
private bool $withSelfVisibility = false;
public function __construct(?Container $container = null)
{
$this->container = $container ?? app();
}
public function withSelfVisibility(): self
{
$this->withSelfVisibility = true;
return $this;
}
/**
* @throws ActivityProviderException
*
* @return array<string, mixed>
*/
public function transform(User $user): array
{
$attributes = [
'id' => $user->getUuid(),
'name' => $user->getName(),
'firstName' => $user->getFirstName(),
'photoUrl' => $user->getPhotoUrl(),
'conferenceRecordPreference' => $user->checkConferenceRecordPreference(),
'conferenceRecordInternalPreference' => $user->checkConferenceRecordInternalPreference(),
// DO NOT USE User::isCrmRequired as it is not hydrated when fetched from ES!
'crmRequired' => $user->crm_required,
'slackFollowUp' => $user->slack_follow_up,
];
// DO NOT USE User::getId as it is not hydrated when fetched from ES!
if ($this->withSelfVisibility || (auth()->check() && auth()->user()->id === $user->id)) {
$softphoneHasVoiceCapability = $user->hasSoftphoneNumberCapabilities()
&& $user->getSoftphoneNumberCapabilities()->hasVoiceCapability()
;
$conferenceSidekickOpen = $user->getConferenceSidekickOpen();
$softphoneSidekickOpen = $user->getSoftphoneSidekickOpen();
$conferenceSidekickPopupOverridden = false;
$softphoneSidekickPopupOverridden = false;
$hasSidekickEnabled = true;
if ($user->getTeam()->hasFeature(FeatureEnum::SIDEKICK_SETTINGS)) {
$sidekickService = $this->getSidekickService();
$sidekickData = $sidekickService->getSidekickSettingsForUser($user);
$conferenceSidekickOpen = $sidekickData['conferenceSettings'];
$softphoneSidekickOpen = $sidekickData['softphoneSettings'];
$conferenceSidekickPopupOverridden = $sidekickData['conferenceSidekickPopupOverridden'];
$softphoneSidekickPopupOverridden = $sidekickData['softphoneSidekickPopupOverridden'];
$hasSidekickEnabled = $sidekickData['sidekickEnabled'];
}
$userService = $this->getUserService();
$dealInsightsPeriod = $userService->getDealInsightTimelinePeriod($user);
$dataFormatCountryCode = $userService->getDateTimeCountryCode($user);
// Attributes for the user only.
$attributes += [
'conferenceJoinReminder' => $user->conference_join_reminder,
'softphoneInboundRecordPreference' => $user->checkSoftphoneInboundRecordPreference(),
'softphoneOutboundRecordPreference' => $user->checkSoftphoneOutboundRecordPreference(),
'softphoneInboundDestination' => $user->softphone_inbound_destination,
'softphoneHasVoiceCapability' => $softphoneHasVoiceCapability,
'softphoneNumber' => $user->getSoftPhoneNumber(),
'formattedSoftphoneNumber' => $user->getFormattedSoftphoneNumberAttribute(),
'email' => $user->getEmailAddress(),
'secondaryEmail' => $user->getSecondaryEmailAddress(),
'phone' => $user->phone,
'secondaryPhone' => $user->secondary_phone,
'callerId' => $user->getCallerId(),
'countryCode' => $user->getCountryCode(),
'timezone' => $user->getTimezone()->getName(),
'language' => $user->getLanguage(),
'locales' => $this->container->get(UserRepository::class)->getUserLocales($user),
'status' => $user->getStatus(),
'hash' => $user->generateHash(),
'registrationDate' => $user->created_at ? $user->created_at->toIso8601String() : null,
'notifyLiveCoaching' => $user->notify_live_coaching,
'activityLogReminder' => $user->activity_log_reminder,
'conferenceSidekickOpen' => $conferenceSidekickOpen,
'softphoneSidekickOpen' => $softphoneSidekickOpen,
'conferenceSidekickPopupOverridden' => $conferenceSidekickPopupOverridden,
'softphoneSidekickPopupOverridden' => $softphoneSidekickPopupOverridden,
'hasSidekickEnabled' => $hasSidekickEnabled,
'activityActionItems' => $user->activity_action_items,
'syncEmail' => $user->isSyncEmailEnabled(),
'syncConference' => $user->sync_conference,
'syncDialer' => $user->shouldSyncDialer(),
'needsToConfigurePhoneNumber' => $this->container
->get('onboarding_phone_decider')
->isOnboardable($user),
'shouldShowPhoneNumberField' => $this->container
->get('onboarding_phone_decider')
->shouldShowPhoneNumberField($user),
UserSetting::DEAL_INSIGHTS_TIMELINE_PERIOD => $dealInsightsPeriod,
'countryByTimezone' => $dataFormatCountryCode,
'conferenceSlug' => $user->getConferenceSlug(),
'conferenceRecordExternalOrganizerPreference' =>
$userService->isConferenceRecordExternalOrganizerPreferenceEnabled($user),
'hasGeneratedAiReports' => $this->getAutomatedReportsRepository()->countUserReports($user) > 0,
'sendEmailWhenExportLinkIsOpened' => $userService->canSendEmailWhenExportLinkIsOpened($user),
];
if ($user->softphone_debug) {
$attributes += [
'debugSoftphone' => $user->softphone_debug, // Needed?
];
}
}
if ($user->getTeam()->getNotificationProvider() === Team::NOTIFICATION_PROVIDER_MSTEAMS) {
$socialAccountMS = $user->getSocialAccount(Team::CALENDAR_PROVIDER_OFFICE);
$state = $socialAccountMS !== null
? str_contains($socialAccountMS->auth_scope, MsTeams::SCOPE_CHAT_CREATE)
: null;
$attributes['integrations']['office'] = [
'displayName' => 'Microsoft Teams',
'apiName' => 'microsoft-teams',
'types' => ['notification'],
'state' => $state ? Provider::STATE_INSTALLED : Provider::STATE_NOT_INSTALLED,
'logo' => cdn('img/ms-teams-logo.svg'),
'installationStrategy' => 'oauth',
];
}
return $attributes;
}
public function includeTeam(User $user): Item
{
$team = $user->getTeam();
return $this->item($team, $this->getTeamTransformer());
}
public function includeGroup(User $user): ?Item
{
$group = $user->getGroup();
if ($group === null) {
return null;
}
return $this->item($group, $this->getGroupTransformer());
}
public function includeJob(User $user): ?Item
{
$job = $user->getJobTitle();
if (! $job instanceof JobTitle) {
return null;
}
return $this->item($job, $this->getJobTitleTransformer());
}
public function includeRoles(User $user): Resource\Collection
{
/** @var Collection<int, string> $roles */
$roles = $user->roles()
->where('is_visible', true)
->pluck('name')
->toArray();
return $this->collection($roles, $this->getRoleTransformer());
}
public function includePermissions(User $user): Resource\Collection
{
$permissions = $user->allPermissions();
return $this->collection($permissions, $this->getPermissionTransformer());
}
public function includeIntegrations(User $user): Item
{
return $this->item($user, $this->getIntegrationsTransformer());
}
private function getTeamTransformer(): TransformerAbstract
{
return $this->container->get(TeamTransformer::class);
}
private function getGroupTransformer(): GroupTransformer
{
return $this->container->get(GroupTransformer::class);
}
private function getIntegrationsTransformer(): IntegrationTransformer
{
return $this->container->get(IntegrationTransformer::class);
}
private function getPermissionTransformer(): PermissionTransformer
{
return $this->container->get(PermissionTransformer::class);
}
private function getRoleTransformer(): RoleTransformer
{
return $this->container->get(RoleTransformer::class);
}
private function getJobTitleTransformer(): JobTitleTransformer
{
return $this->container->get(JobTitleTransformer::class);
}
private function getSidekickService(): SidekickService
{
/** @var SidekickService */
return $this->container->get(SidekickService::class);
}
private function getUserService(): UserService
{
/** @var UserService */
return $this->container->get(UserService::class);
}
private function getAutomatedReportsRepository(): AutomatedReportsRepository
{
/** @var AutomatedReportsRepository */
return $this->container->get(AutomatedReportsRepository::class);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
36
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\DealInsights;
use Doctrine\DBAL\Connection;
use Generator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Jiminny\Component\DealInsights\Forecast\DealData;
use Jiminny\Component\DealInsights\Forecast\DealsFilter;
use Jiminny\Component\DealInsights\QueryBuilder\QueryBuilder;
use Jiminny\Component\DealInsights\QueryBuilder\Visitor\QueryBuilderVisitorInterface;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Stage;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Models;
use Jiminny\Services\Crm\IntegrationApp\DTO\Utils\UrlGeneratorInterface;
use Jiminny\Services\Crm\ProviderRegistry;
use Jiminny\Traits\RequiresUUID;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Eloquent;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class DealsRepository implements DealsRepositoryInterface
{
private Connection $connection;
private ProviderRegistry $providerRegistry;
/**
* @var QueryBuilderVisitorInterface[]
*/
private array $visitors = [];
/**
* @param QueryBuilderVisitorInterface[] $visitors
*/
public function __construct(Connection $connection, ProviderRegistry $crmProviderRegistry, array $visitors = [])
{
$this->connection = $connection;
$this->providerRegistry = $crmProviderRegistry;
foreach ($visitors as $visitor) {
$this->visitors[$visitor->getIdentifier()] = $visitor;
}
}
public function getDeals(CriteriaInterface $criteria): array
{
$context = $criteria->getContext();
$team = $context->getTeam();
$crmService = $this->getCrmService($team);
$qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);
$qb = $this->getSearchSelectAndWhereClauses($qb);
$this->visit($qb, $criteria);
return $this->execute($team, $crmService, $qb);
}
public function getDeal(Team $team, int $id): array
{
$crmService = $this->getCrmService($team);
$qb = $this->createQueryBuilder(QueryBuilder::REALM_DEALS);
$qb = $this->getSearchSelectAndWhereClauses($qb);
$qb->andWhere('opp.id = :id')->setParameter('id', $id);
return $this->execute($team, $crmService, $qb);
}
public function getCrmFieldData(array $crmFields, int $crmId, array $opportunityIds = [])
{
$qb = new QueryBuilder($this->connection);
$qb
->select('f.id', 'f.crm_provider_id AS field_name', 'f.label', 'fd.object_id AS dealId', 'fd.value')
->from('crm_fields', 'f')
->join('f', 'crm_field_data', 'fd', 'fd.crm_field_id = f.id')
->where('f.crm_configuration_id = :crm')
->andWhere('f.object_type = :type')
->andWhere('fd.object_id IN (' . implode(',', $opportunityIds) . ')')
->orderBy('fd.object_id', 'ASC')
->addOrderBy('fd.updated_at', 'ASC')
->setParameter('type', Field::OBJECT_OPPORTUNITY)
->setParameter('crm', $crmId)
;
if (! empty($crmFields)) {
$fields = array_map(fn ($value): string => '"' . $value . '"', $crmFields);
$qb->andWhere('f.crm_provider_id IN (' . implode(',', $fields) . ')');
}
return $qb->executeQuery()->fetchAllAssociative();
}
public function getTotalsInDefaultCurrency(CriteriaInterface $criteria): array
{
$qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);
$qb
->select('SUM(opp.value) as total')
->addSelect('count(*) as `count`')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'))
;
$this->visit($qb, $criteria);
return $qb->executeQuery()->fetchAssociative();
}
public function getTotals(CriteriaInterface $criteria, string $defaultCurrency): array
{
$qb = $this->createQueryBuilder(QueryBuilder::REALM_TOTALS);
$qb
->select('COALESCE(opp.currency_code, "' . $defaultCurrency . '") AS currency')
->addSelect('SUM(opp.value) as total')
->addSelect('count(*) as `count`')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not include deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'))
->groupBy('currency')
;
$this->visit($qb, $criteria);
return $qb->executeQuery()->fetchAllAssociative();
}
public function getDealActivities(CriteriaInterface $criteria): array
{
$qb = Activity::with(['participants', 'user'])
->where('opportunity_id', $criteria->getOpportunityId())
->whereDate('actual_start_time', '>=', $criteria->getPeriod()->getStartDate())
->whereDate('actual_start_time', '<=', $criteria->getPeriod()->getEndDate())
->orderBy($criteria->getSortBy(), $criteria->getSortDirection())
;
// Should we filter activities by criteria? It's intended to filter deals.
return $qb->get()->all();
}
public function getStages(CriteriaInterface $criteria): array
{
$qb = new QueryBuilder($this->connection);
$qb
->select('id', 'label', 'sequence')
->from('stages', 's')
->where('crm_configuration_id = :crm_configuration_id')
->andWhere('type = :type')
->orderBy('sequence', 'ASC')
->setParameter('crm_configuration_id', $criteria->getContext()->getTeam()->getCrmConfiguration()->getId())
->setParameter('type', Stage::TYPE_OPPORTUNITY);
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$result[$row['id']] = [
'label' => $row['label'],
'sequence' => $row['sequence'],
];
}
return $result;
}
public function getConfigurationStages(Configuration $configuration): Collection
{
return $configuration
->stages()
->where('type', Stage::TYPE_OPPORTUNITY)
->get();
}
public function getPipelineData(Configuration $crm): array
{
$qb = new QueryBuilder($this->connection);
$provider = $crm->provider;
$qb
->select('s.label', 's.crm_provider_id', 's.sequence', 'bps.business_process_id AS pipeline_id')
->from('stages', 's')
->join('s', 'business_process_stages', 'bps', 's.id=bps.stage_id')
->where('s.crm_configuration_id = :crm_configuration_id')
->andWhere('s.type = :type')
->orderBy('bps.business_process_id', 'ASC')
->addOrderBy('s.sequence', 'ASC')
->setParameter('crm_configuration_id', $crm->id)
->setParameter('type', Stage::TYPE_OPPORTUNITY)
;
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$value = $provider === Configuration::PROVIDER_SALESFORCE ? $row['label'] : $row['crm_provider_id'];
$result[$row['pipeline_id']][] = [
'value' => $value,
'label' => $row['label'],
'sequence' => $row['sequence'],
];
}
return $result;
}
private function createQueryBuilder(string $realm): QueryBuilder
{
return (new QueryBuilder($this->connection))
->setRealm($realm)
->from('opportunities', 'opp')
->leftJoin('opp', 'record_types', 'rt', 'opp.record_type_id = rt.id')
->leftJoin('opp', 'users', 'usr', 'opp.user_id = usr.id')
->leftJoin('opp', 'accounts', 'acc', 'opp.account_id = acc.id')
;
}
/**
* Applies all applicable visitors and returns the IDs of the executed ones
*
* @return string[]
*/
private function visit(QueryBuilder $queryBuilder, CriteriaInterface $criteria): array
{
$queryVisitors = [];
foreach ($this->visitors as $visitor) {
if ($visitor->isSatisfiedBy($criteria, $queryBuilder->getRealm())) {
$visitor->visit($queryBuilder, $criteria);
$queryVisitors[] = $visitor->getIdentifier();
}
}
return $queryVisitors;
}
private function hydrateStages(array $deals): array
{
foreach ($this->fetchStages(array_keys($deals)) as $stage) {
$oppId = (int) $stage['opportunity_id'];
if (! isset($deals[$oppId])) {
continue; // or throw??!
}
$deals[$oppId]['stages'][] = [
'id' => $stage['stage_id'],
'name' => $stage['label'],
'enteredAt' => $stage['created_at'],
];
}
return $deals;
}
/**
* @param int[] $dealIds
*/
private function fetchStages(array $dealIds): array
{
if (empty($dealIds)) {
return [];
}
$qb = new QueryBuilder($this->connection);
$qb
->select('os.opportunity_id', 's.id AS stage_id', 's.label', 's.created_at')
->from('opportunity_stages', 'os')
->leftJoin('os', 'stages', 's', 'os.stage_id=s.id')
->where($qb->expr()->in('os.opportunity_id', $dealIds))
->orderBy('os.opportunity_id', 'ASC')
->addOrderBy('s.created_at', 'ASC')
;
return $qb->executeQuery()->fetchAllAssociative();
}
private function execute(Team $team, ServiceInterface $crmService, QueryBuilder $qb): array
{
$result = [];
foreach ($qb->executeQuery()->fetchAllAssociative() as $row) {
$data = [
'uuid' => RequiresUUID::toNormal($row['uuid']),
'name' => $row['name'],
'url' => $crmService->generateProviderUrl($row['opp_provider_id'], 'opportunity'),
'account' => [
'name' => $row['acc_name'],
'url' => $crmService->generateProviderUrl(
providerId: $row['acc_provider_id'],
objectType: $row['acc_is_internal'] ? 'internal-account' : 'account'
),
],
'owner' => null,
'rawValue' => [
'amount' => (float) $row['value'],
'currency' => $row['currency_code'],
],
'value' => formatOpportunityValue((float) $row['value'], $row['currency_code']),
'openDate' => $row['remotely_created_at'] ?? null,
'closeDate' => $row['close_date'] ?? null,
'stages' => [],
'currentPipelineId' => $row['pipeline_id'],
'currentStage' => [
'id' => $row['stage_id'],
'enteredAt' => $row['stage_updated_at'],
],
'currentStageUpdatedAt' => $row['stage_updated_at'],
'isClosed' => (bool) $row['is_closed'],
'isWon' => (bool) $row['is_won'],
];
if (isset($row['owner_uuid'])) {
$data['owner'] = [
'uuid' => RequiresUUID::toNormal($row['owner_uuid']),
'name' => $row['owner_name'],
'photoUrl' => $row['owner_photo'] === null
? null
: client_cdn($row['owner_photo'], $team),
'id' => $row['owner_id'],
'job' => $row['owner_job'],
];
}
$result[(int) $row['opp_id']] = $data;
}
return $this->hydrateStages($result);
}
private function getSearchSelectAndWhereClauses(QueryBuilder $queryBuilder): QueryBuilder
{
$qb = clone $queryBuilder;
$qb->leftJoin('usr', 'job_titles', 'jt', 'usr.job_title_id = jt.id');
$qb
->select(...[
'opp.id as opp_id',
'opp.uuid',
'opp.name',
'opp.value',
'opp.currency_code',
'opp.close_date',
'opp.remotely_created_at',
'opp.is_closed',
'opp.is_won',
])
->addSelect(...[
'usr.uuid as owner_uuid',
'usr.name AS owner_name',
'usr.photo_path as owner_photo',
'usr.id AS owner_id',
'jt.name as owner_job',
])
->addSelect('opp.stage_id', 'opp.stage_updated_at')
->addSelect(...[
'acc.name AS acc_name',
'acc.is_internal as acc_is_internal',
'opp.stage_updated_at',
'acc.crm_provider_id AS acc_provider_id',
'opp.crm_provider_id AS opp_provider_id',
])
->addSelect('rt.business_process_id AS pipeline_id')
->where($qb->expr()->isNotNull('opp.user_id')) // we should not display deals owned by external users
->andWhere($qb->expr()->isNull('opp.deleted_at'));
return $qb;
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws SocialAccountTokenInvalidException
*/
private function getCrmService(Team $team): ServiceInterface
{
$crmService = $this->providerRegistry->get($team->crm->provider);
$crmService->setConfiguration($team->crm);
if ($crmService instanceof UrlGeneratorInterface) {
$crmService->setCrmUrlGenerator($team->crm);
}
return $crmService;
}
/**
*
* @return Generator<DealData>
*/
public function getForecastData(DealsFilter $filter): Generator
{
$opportunities = DB::query()
->select([
'o.value',
'o.close_date',
'o.currency_code',
'o.is_won',
'o.is_closed',
'o.probability',
'o.forecast_category',
])
->from('opportunities', 'o')
->join('users', 'users.id', '=', 'o.user_id')
->join('groups', 'groups.id', '=', 'users.group_id')
->where('users.team_id', $filter->getTeam()->getId())
->where('o.close_date', '>=', $filter->getStartDate())
->where('o.close_date', '<=', $filter->getEndDate())
->where('o.currency_code', $filter->getCurrency())
->where('o.deleted_at', '=', null)
;
$userUuidList = $filter->getUserUuidList();
if (! empty($userUuidList)) {
$userUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $userUuidList);
$opportunities->whereIn('users.uuid', $userUuidList);
}
$groupUuidList = $filter->getGroupUuidList();
if (! empty($groupUuidList)) {
$groupUuidList = array_map(fn ($uuid) => RequiresUUID::toOptimized($uuid), $groupUuidList);
$opportunities->whereIn('groups.uuid', $groupUuidList);
}
foreach ($opportunities->cursor() as $row) {
yield new DealData(
(float) $row->value,
$row->close_date,
! empty($row->is_won),
! empty($row->is_closed),
$row->probability ?: 0,
$row->forecast_category ?: '',
);
}
}
public function getUserOpportunitySubscriptions(User $user, array $opportunityIds): Collection
{
return $user->subscriptionSets()
->where(static function (Eloquent\Builder $query): void {
$query
->whereNull('expired_at')
->orWhere('expired_at', '>=', now());
})
->join('activity_subscriptions', function (Builder $join) use ($opportunityIds) {
$join
->on('subscription_set_id', '=', 'activity_subscription_sets.id');
$join
->where('followable_type', Models\Activity\Subscription::FOLLOWABLE_TYPE_OPPORTUNITY)
->whereIn('followable_id', $opportunityIds);
})
->pluck('followable_id');
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
Activity
ActivityAggregator.php, class
ActivityAggregatorInterface.php, interface
DatabaseActivities.php, class
DatasourceInterface.php, interface
RelatedActivity.php, class
RelatedActivityInterface.php, interface
Commands
Comments
Forecast
Jobs
QueryBuilder
Services
ClosingPeriodOptionDecorator.php, class
CreatedPeriodOptionDecorator.php, class
Criteria.php, class
CriteriaInterface.php, interface
CriteriaNormalizer.php, class
CrmService.php, class
CrmServiceInterface.php, interface
DealContactService.php, class
DealInsightsCriteriaBuilder.php, class
DealService.php, class
DealServiceInterface.php, interface
DealsRepository.php, class
DealsRepositoryInterface.php, interface...
|
NULL
|
|
76291
|
1909
|
16
|
2026-04-24T07:40:05.825611+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016405825_m1.jpg...
|
PhpStorm
|
faVsco.js – SendReportNotGeneratedMailJobTest.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
SendReportNotGeneratedMailJobTes…edFormat
Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\AutomatedReports;
use Exception;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Mail;
use Jiminny\Jobs\AutomatedReports\SendReportNotGeneratedMailJob;
use Jiminny\Mail\Reports\ReportNotGenerated;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class SendReportNotGeneratedMailJobTest extends TestCase
{
private LoggerInterface&MockObject $logger;
private SendReportNotGeneratedMailJob $job;
private string $reportUuid = 'test-uuid';
private string $recipientEmail;
private string $recipientName;
private string $reportName;
private string $periodName;
private string $reportsPageUrl;
protected function setUp(): void
{
parent::setUp();
$this->recipientEmail = '[EMAIL]';
$this->recipientName = 'Test User';
$this->reportName = 'Exec Summary';
$this->periodName = 'Q3 2025';
$this->reportsPageUrl = '[URL_WITH_CREDENTIALS] array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SendReportNotGeneratedMailJobTes…edFormat","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Jobs\\AutomatedReports;\n\nuse Exception;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\Mail;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportNotGeneratedMailJob;\nuse Jiminny\\Mail\\Reports\\ReportNotGenerated;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass SendReportNotGeneratedMailJobTest extends TestCase\n{\n private LoggerInterface&MockObject $logger;\n private SendReportNotGeneratedMailJob $job;\n private string $reportUuid = 'test-uuid';\n private string $recipientEmail;\n private string $recipientName;\n private string $reportName;\n private string $periodName;\n private string $reportsPageUrl;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->recipientEmail = 'user@example.com';\n $this->recipientName = 'Test User';\n $this->reportName = 'Exec Summary';\n $this->periodName = 'Q3 2025';\n $this->reportsPageUrl = 'https://app.jiminny.com/reports';\n\n $this->logger = $this->createMock(LoggerInterface::class);\n\n Config::set('app.env', 'testing');\n\n Mail::fake();\n\n $this->job = new SendReportNotGeneratedMailJob(\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl\n );\n }\n\n public function testUniqueIdReturnsExpectedFormat(): void\n {\n $expected = $this->reportUuid . '_not_generated_' . $this->recipientEmail;\n $this->assertEquals($expected, $this->job->uniqueId());\n }\n\n public function testHandleSendsEmailSuccessfully(): void\n {\n Config::set('mail.from.address', 'noreply@jiminny.com');\n Config::set('mail.from.name', 'Jiminny');\n Config::set('jiminny.deploy_region', 'us');\n Config::set('logos.cdn.header', 'https://cdn.test.com/header.png');\n Config::set('logos.cdn.footer', 'https://cdn.test.com/footer.png');\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[Send Report Not Generated Mail] Email sent', [\n 'uuid' => $this->reportUuid,\n 'email' => $this->recipientEmail,\n 'recipientName' => $this->recipientName,\n ]);\n\n $this->job->handle($this->logger);\n\n Mail::assertQueued(ReportNotGenerated::class, function ($mail) {\n return $mail->hasTo($this->recipientEmail);\n });\n }\n\n public function testHandleLogsErrorAndRetriesOnException(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error')\n ->with('[Send Report Not Generated Mail] Error sending email', $this->callback(function ($context) {\n return $context['uuid'] === $this->reportUuid\n && $context['email'] === $this->recipientEmail\n && $context['error'] === 'SMTP error'\n && isset($context['trace']);\n }));\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['release'])\n ->getMock();\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(60);\n\n $jobMock->handle($this->logger);\n }\n\n public function testHandleFailsJobAfterMaxAttempts(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'fail'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(3);\n\n $jobMock->expects($this->once())\n ->method('fail')\n ->with($this->isInstanceOf(Exception::class));\n\n $jobMock->handle($this->logger);\n }\n\n public function testJobPropertiesAreSetCorrectly(): void\n {\n $this->assertEquals(3, $this->job->tries);\n $this->assertEquals([60, 300, 600], $this->job->backoff);\n $this->assertEquals(60, $this->job->timeout);\n }\n\n public function testHandleUsesCorrectBackoffForSecondAttempt(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'release'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(2);\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(300);\n\n $jobMock->handle($this->logger);\n }\n\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Jobs\\AutomatedReports;\n\nuse Exception;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\Mail;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportNotGeneratedMailJob;\nuse Jiminny\\Mail\\Reports\\ReportNotGenerated;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass SendReportNotGeneratedMailJobTest extends TestCase\n{\n private LoggerInterface&MockObject $logger;\n private SendReportNotGeneratedMailJob $job;\n private string $reportUuid = 'test-uuid';\n private string $recipientEmail;\n private string $recipientName;\n private string $reportName;\n private string $periodName;\n private string $reportsPageUrl;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->recipientEmail = 'user@example.com';\n $this->recipientName = 'Test User';\n $this->reportName = 'Exec Summary';\n $this->periodName = 'Q3 2025';\n $this->reportsPageUrl = 'https://app.jiminny.com/reports';\n\n $this->logger = $this->createMock(LoggerInterface::class);\n\n Config::set('app.env', 'testing');\n\n Mail::fake();\n\n $this->job = new SendReportNotGeneratedMailJob(\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl\n );\n }\n\n public function testUniqueIdReturnsExpectedFormat(): void\n {\n $expected = $this->reportUuid . '_not_generated_' . $this->recipientEmail;\n $this->assertEquals($expected, $this->job->uniqueId());\n }\n\n public function testHandleSendsEmailSuccessfully(): void\n {\n Config::set('mail.from.address', 'noreply@jiminny.com');\n Config::set('mail.from.name', 'Jiminny');\n Config::set('jiminny.deploy_region', 'us');\n Config::set('logos.cdn.header', 'https://cdn.test.com/header.png');\n Config::set('logos.cdn.footer', 'https://cdn.test.com/footer.png');\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[Send Report Not Generated Mail] Email sent', [\n 'uuid' => $this->reportUuid,\n 'email' => $this->recipientEmail,\n 'recipientName' => $this->recipientName,\n ]);\n\n $this->job->handle($this->logger);\n\n Mail::assertQueued(ReportNotGenerated::class, function ($mail) {\n return $mail->hasTo($this->recipientEmail);\n });\n }\n\n public function testHandleLogsErrorAndRetriesOnException(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error')\n ->with('[Send Report Not Generated Mail] Error sending email', $this->callback(function ($context) {\n return $context['uuid'] === $this->reportUuid\n && $context['email'] === $this->recipientEmail\n && $context['error'] === 'SMTP error'\n && isset($context['trace']);\n }));\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['release'])\n ->getMock();\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(60);\n\n $jobMock->handle($this->logger);\n }\n\n public function testHandleFailsJobAfterMaxAttempts(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'fail'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(3);\n\n $jobMock->expects($this->once())\n ->method('fail')\n ->with($this->isInstanceOf(Exception::class));\n\n $jobMock->handle($this->logger);\n }\n\n public function testJobPropertiesAreSetCorrectly(): void\n {\n $this->assertEquals(3, $this->job->tries);\n $this->assertEquals([60, 300, 600], $this->job->backoff);\n $this->assertEquals(60, $this->job->timeout);\n }\n\n public function testHandleUsesCorrectBackoffForSecondAttempt(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'release'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(2);\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(300);\n\n $jobMock->handle($this->logger);\n }\n\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-1001287872104142188
|
8405659761666407192
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
SendReportNotGeneratedMailJobTes…edFormat
Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\AutomatedReports;
use Exception;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Mail;
use Jiminny\Jobs\AutomatedReports\SendReportNotGeneratedMailJob;
use Jiminny\Mail\Reports\ReportNotGenerated;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class SendReportNotGeneratedMailJobTest extends TestCase
{
private LoggerInterface&MockObject $logger;
private SendReportNotGeneratedMailJob $job;
private string $reportUuid = 'test-uuid';
private string $recipientEmail;
private string $recipientName;
private string $reportName;
private string $periodName;
private string $reportsPageUrl;
protected function setUp(): void
{
parent::setUp();
$this->recipientEmail = '[EMAIL]';
$this->recipientName = 'Test User';
$this->reportName = 'Exec Summary';
$this->periodName = 'Q3 2025';
$this->reportsPageUrl = '[URL_WITH_CREDENTIALS] array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76292
|
1910
|
15
|
2026-04-24T07:40:05.716376+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016405716_m2.jpg...
|
PhpStorm
|
faVsco.js – SendReportNotGeneratedMailJobTest.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
SendReportNotGeneratedMailJobTes…edFormat
Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\AutomatedReports;
use Exception;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Mail;
use Jiminny\Jobs\AutomatedReports\SendReportNotGeneratedMailJob;
use Jiminny\Mail\Reports\ReportNotGenerated;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class SendReportNotGeneratedMailJobTest extends TestCase
{
private LoggerInterface&MockObject $logger;
private SendReportNotGeneratedMailJob $job;
private string $reportUuid = 'test-uuid';
private string $recipientEmail;
private string $recipientName;
private string $reportName;
private string $periodName;
private string $reportsPageUrl;
protected function setUp(): void
{
parent::setUp();
$this->recipientEmail = '[EMAIL]';
$this->recipientName = 'Test User';
$this->reportName = 'Exec Summary';
$this->periodName = 'Q3 2025';
$this->reportsPageUrl = '[URL_WITH_CREDENTIALS] array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"bounds":{"left":0.8753325,"top":0.89944136,"width":0.100398935,"height":0.013567438},"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"bounds":{"left":0.8753325,"top":0.915403,"width":0.11037234,"height":0.027134877},"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.915403,"width":0.09507979,"height":0.027134877},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.78789896,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SendReportNotGeneratedMailJobTes…edFormat","depth":6,"bounds":{"left":0.8031915,"top":0.019952115,"width":0.11236702,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.58610374,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.59607714,"top":0.32322428,"width":0.00731383,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6050532,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61236703,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Jobs\\AutomatedReports;\n\nuse Exception;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\Mail;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportNotGeneratedMailJob;\nuse Jiminny\\Mail\\Reports\\ReportNotGenerated;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass SendReportNotGeneratedMailJobTest extends TestCase\n{\n private LoggerInterface&MockObject $logger;\n private SendReportNotGeneratedMailJob $job;\n private string $reportUuid = 'test-uuid';\n private string $recipientEmail;\n private string $recipientName;\n private string $reportName;\n private string $periodName;\n private string $reportsPageUrl;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->recipientEmail = 'user@example.com';\n $this->recipientName = 'Test User';\n $this->reportName = 'Exec Summary';\n $this->periodName = 'Q3 2025';\n $this->reportsPageUrl = 'https://app.jiminny.com/reports';\n\n $this->logger = $this->createMock(LoggerInterface::class);\n\n Config::set('app.env', 'testing');\n\n Mail::fake();\n\n $this->job = new SendReportNotGeneratedMailJob(\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl\n );\n }\n\n public function testUniqueIdReturnsExpectedFormat(): void\n {\n $expected = $this->reportUuid . '_not_generated_' . $this->recipientEmail;\n $this->assertEquals($expected, $this->job->uniqueId());\n }\n\n public function testHandleSendsEmailSuccessfully(): void\n {\n Config::set('mail.from.address', 'noreply@jiminny.com');\n Config::set('mail.from.name', 'Jiminny');\n Config::set('jiminny.deploy_region', 'us');\n Config::set('logos.cdn.header', 'https://cdn.test.com/header.png');\n Config::set('logos.cdn.footer', 'https://cdn.test.com/footer.png');\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[Send Report Not Generated Mail] Email sent', [\n 'uuid' => $this->reportUuid,\n 'email' => $this->recipientEmail,\n 'recipientName' => $this->recipientName,\n ]);\n\n $this->job->handle($this->logger);\n\n Mail::assertQueued(ReportNotGenerated::class, function ($mail) {\n return $mail->hasTo($this->recipientEmail);\n });\n }\n\n public function testHandleLogsErrorAndRetriesOnException(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error')\n ->with('[Send Report Not Generated Mail] Error sending email', $this->callback(function ($context) {\n return $context['uuid'] === $this->reportUuid\n && $context['email'] === $this->recipientEmail\n && $context['error'] === 'SMTP error'\n && isset($context['trace']);\n }));\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['release'])\n ->getMock();\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(60);\n\n $jobMock->handle($this->logger);\n }\n\n public function testHandleFailsJobAfterMaxAttempts(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'fail'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(3);\n\n $jobMock->expects($this->once())\n ->method('fail')\n ->with($this->isInstanceOf(Exception::class));\n\n $jobMock->handle($this->logger);\n }\n\n public function testJobPropertiesAreSetCorrectly(): void\n {\n $this->assertEquals(3, $this->job->tries);\n $this->assertEquals([60, 300, 600], $this->job->backoff);\n $this->assertEquals(60, $this->job->timeout);\n }\n\n public function testHandleUsesCorrectBackoffForSecondAttempt(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'release'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(2);\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(300);\n\n $jobMock->handle($this->logger);\n }\n\n}","depth":4,"bounds":{"left":0.3799867,"top":0.3200319,"width":0.2393617,"height":0.6799681},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Jobs\\AutomatedReports;\n\nuse Exception;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\Mail;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportNotGeneratedMailJob;\nuse Jiminny\\Mail\\Reports\\ReportNotGenerated;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass SendReportNotGeneratedMailJobTest extends TestCase\n{\n private LoggerInterface&MockObject $logger;\n private SendReportNotGeneratedMailJob $job;\n private string $reportUuid = 'test-uuid';\n private string $recipientEmail;\n private string $recipientName;\n private string $reportName;\n private string $periodName;\n private string $reportsPageUrl;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->recipientEmail = 'user@example.com';\n $this->recipientName = 'Test User';\n $this->reportName = 'Exec Summary';\n $this->periodName = 'Q3 2025';\n $this->reportsPageUrl = 'https://app.jiminny.com/reports';\n\n $this->logger = $this->createMock(LoggerInterface::class);\n\n Config::set('app.env', 'testing');\n\n Mail::fake();\n\n $this->job = new SendReportNotGeneratedMailJob(\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl\n );\n }\n\n public function testUniqueIdReturnsExpectedFormat(): void\n {\n $expected = $this->reportUuid . '_not_generated_' . $this->recipientEmail;\n $this->assertEquals($expected, $this->job->uniqueId());\n }\n\n public function testHandleSendsEmailSuccessfully(): void\n {\n Config::set('mail.from.address', 'noreply@jiminny.com');\n Config::set('mail.from.name', 'Jiminny');\n Config::set('jiminny.deploy_region', 'us');\n Config::set('logos.cdn.header', 'https://cdn.test.com/header.png');\n Config::set('logos.cdn.footer', 'https://cdn.test.com/footer.png');\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[Send Report Not Generated Mail] Email sent', [\n 'uuid' => $this->reportUuid,\n 'email' => $this->recipientEmail,\n 'recipientName' => $this->recipientName,\n ]);\n\n $this->job->handle($this->logger);\n\n Mail::assertQueued(ReportNotGenerated::class, function ($mail) {\n return $mail->hasTo($this->recipientEmail);\n });\n }\n\n public function testHandleLogsErrorAndRetriesOnException(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error')\n ->with('[Send Report Not Generated Mail] Error sending email', $this->callback(function ($context) {\n return $context['uuid'] === $this->reportUuid\n && $context['email'] === $this->recipientEmail\n && $context['error'] === 'SMTP error'\n && isset($context['trace']);\n }));\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['release'])\n ->getMock();\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(60);\n\n $jobMock->handle($this->logger);\n }\n\n public function testHandleFailsJobAfterMaxAttempts(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'fail'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(3);\n\n $jobMock->expects($this->once())\n ->method('fail')\n ->with($this->isInstanceOf(Exception::class));\n\n $jobMock->handle($this->logger);\n }\n\n public function testJobPropertiesAreSetCorrectly(): void\n {\n $this->assertEquals(3, $this->job->tries);\n $this->assertEquals([60, 300, 600], $this->job->backoff);\n $this->assertEquals(60, $this->job->timeout);\n }\n\n public function testHandleUsesCorrectBackoffForSecondAttempt(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'release'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(2);\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(300);\n\n $jobMock->handle($this->logger);\n }\n\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-1001287872104142188
|
8405659761666407192
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
SendReportNotGeneratedMailJobTes…edFormat
Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\AutomatedReports;
use Exception;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Mail;
use Jiminny\Jobs\AutomatedReports\SendReportNotGeneratedMailJob;
use Jiminny\Mail\Reports\ReportNotGenerated;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class SendReportNotGeneratedMailJobTest extends TestCase
{
private LoggerInterface&MockObject $logger;
private SendReportNotGeneratedMailJob $job;
private string $reportUuid = 'test-uuid';
private string $recipientEmail;
private string $recipientName;
private string $reportName;
private string $periodName;
private string $reportsPageUrl;
protected function setUp(): void
{
parent::setUp();
$this->recipientEmail = '[EMAIL]';
$this->recipientName = 'Test User';
$this->reportName = 'Exec Summary';
$this->periodName = 'Q3 2025';
$this->reportsPageUrl = '[URL_WITH_CREDENTIALS] array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76289
|
|
76286
|
1909
|
13
|
2026-04-24T07:39:55.012525+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016395012_m1.jpg...
|
PhpStorm
|
faVsco.js – SendReportNotGeneratedMailJobTest.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
SendReportNotGeneratedMailJobTes…edFormat
Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
3
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\AutomatedReports;
use Exception;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Mail;
use Jiminny\Jobs\AutomatedReports\SendReportNotGeneratedMailJob;
use Jiminny\Mail\Reports\ReportNotGenerated;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class SendReportNotGeneratedMailJobTest extends TestCase
{
private LoggerInterface&MockObject $logger;
private SendReportNotGeneratedMailJob $job;
private string $reportUuid = 'test-uuid';
private string $recipientEmail;
private string $recipientName;
private string $reportName;
private string $periodName;
private string $reportsPageUrl;
protected function setUp(): void
{
parent::setUp();
$this->recipientEmail = '[EMAIL]';
$this->recipientName = 'Test User';
$this->reportName = 'Exec Summary';
$this->periodName = 'Q3 2025';
$this->reportsPageUrl = '[URL_WITH_CREDENTIALS] array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SendReportNotGeneratedMailJobTes…edFormat","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Jobs\\AutomatedReports;\n\nuse Exception;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\Mail;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportNotGeneratedMailJob;\nuse Jiminny\\Mail\\Reports\\ReportNotGenerated;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass SendReportNotGeneratedMailJobTest extends TestCase\n{\n private LoggerInterface&MockObject $logger;\n private SendReportNotGeneratedMailJob $job;\n private string $reportUuid = 'test-uuid';\n private string $recipientEmail;\n private string $recipientName;\n private string $reportName;\n private string $periodName;\n private string $reportsPageUrl;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->recipientEmail = 'user@example.com';\n $this->recipientName = 'Test User';\n $this->reportName = 'Exec Summary';\n $this->periodName = 'Q3 2025';\n $this->reportsPageUrl = 'https://app.jiminny.com/reports';\n\n $this->logger = $this->createMock(LoggerInterface::class);\n\n Config::set('app.env', 'testing');\n\n Mail::fake();\n\n $this->job = new SendReportNotGeneratedMailJob(\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl\n );\n }\n\n public function testUniqueIdReturnsExpectedFormat(): void\n {\n $expected = $this->reportUuid . '_not_generated_' . $this->recipientEmail;\n $this->assertEquals($expected, $this->job->uniqueId());\n }\n\n public function testHandleSendsEmailSuccessfully(): void\n {\n Config::set('mail.from.address', 'noreply@jiminny.com');\n Config::set('mail.from.name', 'Jiminny');\n Config::set('jiminny.deploy_region', 'us');\n Config::set('logos.cdn.header', 'https://cdn.test.com/header.png');\n Config::set('logos.cdn.footer', 'https://cdn.test.com/footer.png');\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[Send Report Not Generated Mail] Email sent', [\n 'uuid' => $this->reportUuid,\n 'email' => $this->recipientEmail,\n 'recipientName' => $this->recipientName,\n ]);\n\n $this->job->handle($this->logger);\n\n Mail::assertQueued(ReportNotGenerated::class, function ($mail) {\n return $mail->hasTo($this->recipientEmail);\n });\n }\n\n public function testHandleLogsErrorAndRetriesOnException(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error')\n ->with('[Send Report Not Generated Mail] Error sending email', $this->callback(function ($context) {\n return $context['uuid'] === $this->reportUuid\n && $context['email'] === $this->recipientEmail\n && $context['error'] === 'SMTP error'\n && isset($context['trace']);\n }));\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['release'])\n ->getMock();\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(60);\n\n $jobMock->handle($this->logger);\n }\n\n public function testHandleFailsJobAfterMaxAttempts(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'fail'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(3);\n\n $jobMock->expects($this->once())\n ->method('fail')\n ->with($this->isInstanceOf(Exception::class));\n\n $jobMock->handle($this->logger);\n }\n\n public function testJobPropertiesAreSetCorrectly(): void\n {\n $this->assertEquals(3, $this->job->tries);\n $this->assertEquals([60, 300, 600], $this->job->backoff);\n $this->assertEquals(60, $this->job->timeout);\n }\n\n public function testHandleUsesCorrectBackoffForSecondAttempt(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'release'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(2);\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(300);\n\n $jobMock->handle($this->logger);\n }\n\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Jobs\\AutomatedReports;\n\nuse Exception;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\Mail;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportNotGeneratedMailJob;\nuse Jiminny\\Mail\\Reports\\ReportNotGenerated;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass SendReportNotGeneratedMailJobTest extends TestCase\n{\n private LoggerInterface&MockObject $logger;\n private SendReportNotGeneratedMailJob $job;\n private string $reportUuid = 'test-uuid';\n private string $recipientEmail;\n private string $recipientName;\n private string $reportName;\n private string $periodName;\n private string $reportsPageUrl;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->recipientEmail = 'user@example.com';\n $this->recipientName = 'Test User';\n $this->reportName = 'Exec Summary';\n $this->periodName = 'Q3 2025';\n $this->reportsPageUrl = 'https://app.jiminny.com/reports';\n\n $this->logger = $this->createMock(LoggerInterface::class);\n\n Config::set('app.env', 'testing');\n\n Mail::fake();\n\n $this->job = new SendReportNotGeneratedMailJob(\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl\n );\n }\n\n public function testUniqueIdReturnsExpectedFormat(): void\n {\n $expected = $this->reportUuid . '_not_generated_' . $this->recipientEmail;\n $this->assertEquals($expected, $this->job->uniqueId());\n }\n\n public function testHandleSendsEmailSuccessfully(): void\n {\n Config::set('mail.from.address', 'noreply@jiminny.com');\n Config::set('mail.from.name', 'Jiminny');\n Config::set('jiminny.deploy_region', 'us');\n Config::set('logos.cdn.header', 'https://cdn.test.com/header.png');\n Config::set('logos.cdn.footer', 'https://cdn.test.com/footer.png');\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[Send Report Not Generated Mail] Email sent', [\n 'uuid' => $this->reportUuid,\n 'email' => $this->recipientEmail,\n 'recipientName' => $this->recipientName,\n ]);\n\n $this->job->handle($this->logger);\n\n Mail::assertQueued(ReportNotGenerated::class, function ($mail) {\n return $mail->hasTo($this->recipientEmail);\n });\n }\n\n public function testHandleLogsErrorAndRetriesOnException(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error')\n ->with('[Send Report Not Generated Mail] Error sending email', $this->callback(function ($context) {\n return $context['uuid'] === $this->reportUuid\n && $context['email'] === $this->recipientEmail\n && $context['error'] === 'SMTP error'\n && isset($context['trace']);\n }));\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['release'])\n ->getMock();\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(60);\n\n $jobMock->handle($this->logger);\n }\n\n public function testHandleFailsJobAfterMaxAttempts(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'fail'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(3);\n\n $jobMock->expects($this->once())\n ->method('fail')\n ->with($this->isInstanceOf(Exception::class));\n\n $jobMock->handle($this->logger);\n }\n\n public function testJobPropertiesAreSetCorrectly(): void\n {\n $this->assertEquals(3, $this->job->tries);\n $this->assertEquals([60, 300, 600], $this->job->backoff);\n $this->assertEquals(60, $this->job->timeout);\n }\n\n public function testHandleUsesCorrectBackoffForSecondAttempt(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'release'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(2);\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(300);\n\n $jobMock->handle($this->logger);\n }\n\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5346950300665258389
|
8405655363615669016
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
SendReportNotGeneratedMailJobTes…edFormat
Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
3
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\AutomatedReports;
use Exception;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Mail;
use Jiminny\Jobs\AutomatedReports\SendReportNotGeneratedMailJob;
use Jiminny\Mail\Reports\ReportNotGenerated;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class SendReportNotGeneratedMailJobTest extends TestCase
{
private LoggerInterface&MockObject $logger;
private SendReportNotGeneratedMailJob $job;
private string $reportUuid = 'test-uuid';
private string $recipientEmail;
private string $recipientName;
private string $reportName;
private string $periodName;
private string $reportsPageUrl;
protected function setUp(): void
{
parent::setUp();
$this->recipientEmail = '[EMAIL]';
$this->recipientName = 'Test User';
$this->reportName = 'Exec Summary';
$this->periodName = 'Q3 2025';
$this->reportsPageUrl = '[URL_WITH_CREDENTIALS] array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76284
|
|
76287
|
1910
|
13
|
2026-04-24T07:39:55.012487+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016395012_m2.jpg...
|
PhpStorm
|
faVsco.js – SendReportNotGeneratedMailJobTest.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
SendReportNotGeneratedMailJobTes…edFormat
Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
3
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\AutomatedReports;
use Exception;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Mail;
use Jiminny\Jobs\AutomatedReports\SendReportNotGeneratedMailJob;
use Jiminny\Mail\Reports\ReportNotGenerated;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class SendReportNotGeneratedMailJobTest extends TestCase
{
private LoggerInterface&MockObject $logger;
private SendReportNotGeneratedMailJob $job;
private string $reportUuid = 'test-uuid';
private string $recipientEmail;
private string $recipientName;
private string $reportName;
private string $periodName;
private string $reportsPageUrl;
protected function setUp(): void
{
parent::setUp();
$this->recipientEmail = '[EMAIL]';
$this->recipientName = 'Test User';
$this->reportName = 'Exec Summary';
$this->periodName = 'Q3 2025';
$this->reportsPageUrl = '[URL_WITH_CREDENTIALS] array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"bounds":{"left":0.8753325,"top":0.89944136,"width":0.100398935,"height":0.013567438},"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"bounds":{"left":0.8753325,"top":0.915403,"width":0.11037234,"height":0.027134877},"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.915403,"width":0.09507979,"height":0.027134877},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.78789896,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SendReportNotGeneratedMailJobTes…edFormat","depth":6,"bounds":{"left":0.8031915,"top":0.019952115,"width":0.11236702,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.58610374,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.59607714,"top":0.32322428,"width":0.00731383,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6050532,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61236703,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Jobs\\AutomatedReports;\n\nuse Exception;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\Mail;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportNotGeneratedMailJob;\nuse Jiminny\\Mail\\Reports\\ReportNotGenerated;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass SendReportNotGeneratedMailJobTest extends TestCase\n{\n private LoggerInterface&MockObject $logger;\n private SendReportNotGeneratedMailJob $job;\n private string $reportUuid = 'test-uuid';\n private string $recipientEmail;\n private string $recipientName;\n private string $reportName;\n private string $periodName;\n private string $reportsPageUrl;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->recipientEmail = 'user@example.com';\n $this->recipientName = 'Test User';\n $this->reportName = 'Exec Summary';\n $this->periodName = 'Q3 2025';\n $this->reportsPageUrl = 'https://app.jiminny.com/reports';\n\n $this->logger = $this->createMock(LoggerInterface::class);\n\n Config::set('app.env', 'testing');\n\n Mail::fake();\n\n $this->job = new SendReportNotGeneratedMailJob(\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl\n );\n }\n\n public function testUniqueIdReturnsExpectedFormat(): void\n {\n $expected = $this->reportUuid . '_not_generated_' . $this->recipientEmail;\n $this->assertEquals($expected, $this->job->uniqueId());\n }\n\n public function testHandleSendsEmailSuccessfully(): void\n {\n Config::set('mail.from.address', 'noreply@jiminny.com');\n Config::set('mail.from.name', 'Jiminny');\n Config::set('jiminny.deploy_region', 'us');\n Config::set('logos.cdn.header', 'https://cdn.test.com/header.png');\n Config::set('logos.cdn.footer', 'https://cdn.test.com/footer.png');\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[Send Report Not Generated Mail] Email sent', [\n 'uuid' => $this->reportUuid,\n 'email' => $this->recipientEmail,\n 'recipientName' => $this->recipientName,\n ]);\n\n $this->job->handle($this->logger);\n\n Mail::assertQueued(ReportNotGenerated::class, function ($mail) {\n return $mail->hasTo($this->recipientEmail);\n });\n }\n\n public function testHandleLogsErrorAndRetriesOnException(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error')\n ->with('[Send Report Not Generated Mail] Error sending email', $this->callback(function ($context) {\n return $context['uuid'] === $this->reportUuid\n && $context['email'] === $this->recipientEmail\n && $context['error'] === 'SMTP error'\n && isset($context['trace']);\n }));\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['release'])\n ->getMock();\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(60);\n\n $jobMock->handle($this->logger);\n }\n\n public function testHandleFailsJobAfterMaxAttempts(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'fail'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(3);\n\n $jobMock->expects($this->once())\n ->method('fail')\n ->with($this->isInstanceOf(Exception::class));\n\n $jobMock->handle($this->logger);\n }\n\n public function testJobPropertiesAreSetCorrectly(): void\n {\n $this->assertEquals(3, $this->job->tries);\n $this->assertEquals([60, 300, 600], $this->job->backoff);\n $this->assertEquals(60, $this->job->timeout);\n }\n\n public function testHandleUsesCorrectBackoffForSecondAttempt(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'release'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(2);\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(300);\n\n $jobMock->handle($this->logger);\n }\n\n}","depth":4,"bounds":{"left":0.3799867,"top":0.013567438,"width":0.2393617,"height":0.9656824},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Jobs\\AutomatedReports;\n\nuse Exception;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\Mail;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportNotGeneratedMailJob;\nuse Jiminny\\Mail\\Reports\\ReportNotGenerated;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass SendReportNotGeneratedMailJobTest extends TestCase\n{\n private LoggerInterface&MockObject $logger;\n private SendReportNotGeneratedMailJob $job;\n private string $reportUuid = 'test-uuid';\n private string $recipientEmail;\n private string $recipientName;\n private string $reportName;\n private string $periodName;\n private string $reportsPageUrl;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->recipientEmail = 'user@example.com';\n $this->recipientName = 'Test User';\n $this->reportName = 'Exec Summary';\n $this->periodName = 'Q3 2025';\n $this->reportsPageUrl = 'https://app.jiminny.com/reports';\n\n $this->logger = $this->createMock(LoggerInterface::class);\n\n Config::set('app.env', 'testing');\n\n Mail::fake();\n\n $this->job = new SendReportNotGeneratedMailJob(\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl\n );\n }\n\n public function testUniqueIdReturnsExpectedFormat(): void\n {\n $expected = $this->reportUuid . '_not_generated_' . $this->recipientEmail;\n $this->assertEquals($expected, $this->job->uniqueId());\n }\n\n public function testHandleSendsEmailSuccessfully(): void\n {\n Config::set('mail.from.address', 'noreply@jiminny.com');\n Config::set('mail.from.name', 'Jiminny');\n Config::set('jiminny.deploy_region', 'us');\n Config::set('logos.cdn.header', 'https://cdn.test.com/header.png');\n Config::set('logos.cdn.footer', 'https://cdn.test.com/footer.png');\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[Send Report Not Generated Mail] Email sent', [\n 'uuid' => $this->reportUuid,\n 'email' => $this->recipientEmail,\n 'recipientName' => $this->recipientName,\n ]);\n\n $this->job->handle($this->logger);\n\n Mail::assertQueued(ReportNotGenerated::class, function ($mail) {\n return $mail->hasTo($this->recipientEmail);\n });\n }\n\n public function testHandleLogsErrorAndRetriesOnException(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error')\n ->with('[Send Report Not Generated Mail] Error sending email', $this->callback(function ($context) {\n return $context['uuid'] === $this->reportUuid\n && $context['email'] === $this->recipientEmail\n && $context['error'] === 'SMTP error'\n && isset($context['trace']);\n }));\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['release'])\n ->getMock();\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(60);\n\n $jobMock->handle($this->logger);\n }\n\n public function testHandleFailsJobAfterMaxAttempts(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->with($this->recipientEmail)\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'fail'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(3);\n\n $jobMock->expects($this->once())\n ->method('fail')\n ->with($this->isInstanceOf(Exception::class));\n\n $jobMock->handle($this->logger);\n }\n\n public function testJobPropertiesAreSetCorrectly(): void\n {\n $this->assertEquals(3, $this->job->tries);\n $this->assertEquals([60, 300, 600], $this->job->backoff);\n $this->assertEquals(60, $this->job->timeout);\n }\n\n public function testHandleUsesCorrectBackoffForSecondAttempt(): void\n {\n Mail::shouldReceive('mailer')\n ->with('postmark')\n ->andReturnSelf()\n ->shouldReceive('to')\n ->andThrow(new Exception('SMTP error'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $jobMock = $this->getMockBuilder(SendReportNotGeneratedMailJob::class)\n ->setConstructorArgs([\n $this->reportUuid,\n $this->recipientEmail,\n $this->recipientName,\n $this->reportName,\n $this->periodName,\n $this->reportsPageUrl,\n ])\n ->onlyMethods(['attempts', 'release'])\n ->getMock();\n\n $jobMock->expects($this->atLeastOnce())\n ->method('attempts')\n ->willReturn(2);\n\n $jobMock->expects($this->once())\n ->method('release')\n ->with(300);\n\n $jobMock->handle($this->logger);\n }\n\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5346950300665258389
|
8405655363615669016
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
SendReportNotGeneratedMailJobTes…edFormat
Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
3
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\AutomatedReports;
use Exception;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Mail;
use Jiminny\Jobs\AutomatedReports\SendReportNotGeneratedMailJob;
use Jiminny\Mail\Reports\ReportNotGenerated;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class SendReportNotGeneratedMailJobTest extends TestCase
{
private LoggerInterface&MockObject $logger;
private SendReportNotGeneratedMailJob $job;
private string $reportUuid = 'test-uuid';
private string $recipientEmail;
private string $recipientName;
private string $reportName;
private string $periodName;
private string $reportsPageUrl;
protected function setUp(): void
{
parent::setUp();
$this->recipientEmail = '[EMAIL]';
$this->recipientName = 'Test User';
$this->reportName = 'Exec Summary';
$this->periodName = 'Q3 2025';
$this->reportsPageUrl = '[URL_WITH_CREDENTIALS] array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76285
|
|
76776
|
1925
|
19
|
2026-04-24T08:24:46.691456+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019086691_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4884021265479652975
|
8405593994972867482
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide...
|
76772
|
|
76778
|
1925
|
20
|
2026-04-24T08:24:48.085560+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019088085_m1.jpg...
|
PhpStorm
|
faVsco.js – custom.log
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder
.circleci, folder
.cursor, folder
.github
.sonarlint, folder
.vscode, folder
.windsurf, folder
app, sources root
Actions, folder
Component, folder
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder
FileSystem, folder
Gecko, folder
Gong, folder
GuzzleHttp, folder
KeyPoints, folder
Kiosk, folder...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app, folder","depth":6,"role_description":"text"},{"role":"AXStaticText","text":".circleci, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".cursor, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".vscode, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".windsurf, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"Actions, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Component, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Acl, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activity, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Dtos, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Events, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AWS, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Cache, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Country, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Database, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Datadog, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DateTime, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Encoding, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Encryption, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ES, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Faker, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Gecko, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Gong, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk, folder","depth":9,"role_description":"text"}]...
|
-5687799803346889642
|
8405592758022155034
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder
.circleci, folder
.cursor, folder
.github
.sonarlint, folder
.vscode, folder
.windsurf, folder
app, sources root
Actions, folder
Component, folder
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder
FileSystem, folder
Gecko, folder
Gong, folder
GuzzleHttp, folder
KeyPoints, folder
Kiosk, folder...
|
NULL
|
|
76266
|
1909
|
3
|
2026-04-24T07:39:01.396415+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016341396_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8258260772794833742
|
8404748264376863642
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide...
|
76265
|
|
76267
|
1910
|
3
|
2026-04-24T07:39:01.342781+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016341342_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"bounds":{"left":0.8753325,"top":0.89944136,"width":0.100398935,"height":0.013567438},"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"bounds":{"left":0.8753325,"top":0.915403,"width":0.11037234,"height":0.027134877},"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.915403,"width":0.09507979,"height":0.027134877},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59541225,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6050532,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61236703,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.0,"width":0.34375,"height":1.0},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8411209987128727906
|
8404748264376863642
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes...
|
76264
|
|
76211
|
1907
|
26
|
2026-04-24T07:36:39.394013+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016199394_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Patch successfully applied
text/html
text/html
tex Patch successfully applied
text/html
text/html
text/html
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Patch successfully applied","depth":3,"value":"Patch successfully applied","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
6595782366022348956
|
8404748264372669338
|
click
|
accessibility
|
NULL
|
Patch successfully applied
text/html
text/html
tex Patch successfully applied
text/html
text/html
text/html
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification...
|
NULL
|
|
52541
|
1137
|
25
|
2026-04-20T07:21:29.324879+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776669689324_m2.jpg...
|
PhpStorm
|
faVsco.js – console [EU]
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Laravel Idea: Generate Helper Code?
Helper Code wi Laravel Idea: Generate Helper Code?
Helper Code will help IDE to understand your Laravel app code.
text/html
text/html
text/html
Generate
Don't Show Anymore
More
The Hunspell plugin has been deprecated. If you're not writing in Hungarian, you can safely uninstall Hunspell without affecting the dictionaries for other languages.
text/html
text/html
text/html
Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
11
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Laravel Idea: Generate Helper Code?","depth":2,"bounds":{"left":0.8753325,"top":0.8172386,"width":0.100398935,"height":0.013567438},"role_description":"text"},{"role":"AXTextField","text":"Helper Code will help IDE to understand your Laravel app code.","depth":3,"bounds":{"left":0.8753325,"top":0.83320034,"width":0.11037234,"height":0.027134877},"value":"Helper Code will help IDE to understand your Laravel app code.","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.83320034,"width":0.09275266,"height":0.027134877},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Generate","depth":2,"bounds":{"left":0.8753325,"top":0.8659218,"width":0.018949468,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Don't Show Anymore","depth":2,"bounds":{"left":0.89960104,"top":0.8659218,"width":0.04288564,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"More","depth":2,"bounds":{"left":0.27027926,"top":1.0,"width":0.016289894,"height":0.0},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"The Hunspell plugin has been deprecated. If you're not writing in Hungarian, you can safely uninstall Hunspell without affecting the dictionaries for other languages.","depth":3,"bounds":{"left":0.8753325,"top":0.9074222,"width":0.11037234,"height":0.054269753},"value":"The Hunspell plugin has been deprecated. If you're not writing in Hungarian, you can safely uninstall Hunspell without affecting the dictionaries for other languages.","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.9074222,"width":0.095744684,"height":0.054269753},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.36868352,"top":0.2490024,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"11","depth":4,"bounds":{"left":0.37865692,"top":0.2490024,"width":0.008976064,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.38929522,"top":0.24740623,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.39660904,"top":0.24740623,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4891451058990452583
|
8404467957765491610
|
visual_change
|
accessibility
|
NULL
|
Laravel Idea: Generate Helper Code?
Helper Code wi Laravel Idea: Generate Helper Code?
Helper Code will help IDE to understand your Laravel app code.
text/html
text/html
text/html
Generate
Don't Show Anymore
More
The Hunspell plugin has been deprecated. If you're not writing in Hungarian, you can safely uninstall Hunspell without affecting the dictionaries for other languages.
text/html
text/html
text/html
Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
11
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}...
|
NULL
|
|
52537
|
1136
|
19
|
2026-04-20T07:21:26.073799+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776669686073_m1.jpg...
|
PhpStorm
|
faVsco.js – console [EU]
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Laravel Idea: Generate Helper Code?
Helper Code wi Laravel Idea: Generate Helper Code?
Helper Code will help IDE to understand your Laravel app code.
text/html
text/html
text/html
Generate
Don't Show Anymore
More
The Hunspell plugin has been deprecated. If you're not writing in Hungarian, you can safely uninstall Hunspell without affecting the dictionaries for other languages.
text/html
text/html
text/html
Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
11
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Laravel Idea: Generate Helper Code?","depth":2,"role_description":"text"},{"role":"AXTextField","text":"Helper Code will help IDE to understand your Laravel app code.","depth":3,"value":"Helper Code will help IDE to understand your Laravel app code.","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Generate","depth":2,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Don't Show Anymore","depth":2,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"More","depth":2,"bounds":{"left":0.0,"top":0.0,"width":0.034027778,"height":0.018888889},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"The Hunspell plugin has been deprecated. If you're not writing in Hungarian, you can safely uninstall Hunspell without affecting the dictionaries for other languages.","depth":3,"value":"The Hunspell plugin has been deprecated. If you're not writing in Hungarian, you can safely uninstall Hunspell without affecting the dictionaries for other languages.","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"11","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7420632223208125730
|
8404467957698366362
|
click
|
accessibility
|
NULL
|
Laravel Idea: Generate Helper Code?
Helper Code wi Laravel Idea: Generate Helper Code?
Helper Code will help IDE to understand your Laravel app code.
text/html
text/html
text/html
Generate
Don't Show Anymore
More
The Hunspell plugin has been deprecated. If you're not writing in Hungarian, you can safely uninstall Hunspell without affecting the dictionaries for other languages.
text/html
text/html
text/html
Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
11
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto...
|
NULL
|
|
52115
|
1127
|
27
|
2026-04-20T06:40:01.595018+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776667201595_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
4
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXStaticText","text":"8","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7585605862760607160
|
8404467957564156826
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
4
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}...
|
52114
|
|
52116
|
1126
|
27
|
2026-04-20T06:40:02.243170+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776667202243_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
4
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"role_description":"text"},{"role":"AXStaticText","text":"8","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.014583333,"height":0.025555555},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7585605862760607160
|
8404467957564156826
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
4
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}...
|
52111
|
|
52166
|
1129
|
5
|
2026-04-20T06:42:50.311905+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776667370311_m2.jpg...
|
PhpStorm
|
faVsco.js – console [EU]
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
4
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXStaticText","text":"8","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7585605862760607160
|
8404467957564156826
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
4
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}...
|
52164
|
|
52662
|
1139
|
41
|
2026-04-20T07:27:48.997692+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776670068997_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
6
11
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXStaticText","text":"11","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008976064,"height":0.0},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.40492022,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"bounds":{"left":0.41356382,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"bounds":{"left":0.4245346,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"bounds":{"left":0.4331782,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"bounds":{"left":0.4418218,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"bounds":{"left":0.45279256,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.4637633,"top":0.09896249,"width":0.024268618,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.49035904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.5013298,"top":0.09896249,"width":0.029587766,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.69913566,"top":0.09896249,"width":0.02825798,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
2066644074886763499
|
8404467957564148634
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
6
11
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:...
|
52656
|
|
52687
|
1140
|
5
|
2026-04-20T07:29:52.930386+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776670192930_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
6
11
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"11","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn(null);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
2066644074886763499
|
8404467957564148634
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
6
11
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksCreatorForAskJiminnyReportWithNullFrequency(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn(null);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => null]
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->once())->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:...
|
52684
|
|
76784
|
1925
|
23
|
2026-04-24T08:24:54.235372+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019094235_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder
.circleci, folder
.cursor, folder
.github
.sonarlint, folder
.vscode, folder
.windsurf, folder
app, sources root
Actions, folder
Component, folder
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder
FileSystem, folder
Gecko, folder
Gong, folder
GuzzleHttp, folder
KeyPoints, folder
Kiosk, folder
LanguageDetection, folder
LiveFeed, folder
Locks, folder
Math, folder
MediaPipeline, folder
MeetingBot, folder
MobileSettings, folder
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage, folder
Playlist, folder
Prophet, folder
ProphetAi, folder
ProsperWorks, folder
Queue, folder
Router, folder
Saml2, folder
SCIM, folder
Seeder, folder
Sentry, folder
Serializer, folder
Settings, folder
Sidekick, folder
Slack, folder
TeamInsights, folder
TimeMemoryMapper, folder
Transcription, folder
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration, folder
Console, folder
Commands, folder
Activities, folder
Analytics, folder
Calendars, folder
Crm, folder
Hubspot, folder
IntegrationApp, folder
Traits, folder
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php, class
BullhornSessionCommand.php, class
CheckActivityLoggableCommand.php, final class
CleanDuplicateFieldDataCommand.php, class
FullSyncOpportunityCommand.php, class
LogActivitiesCommand.php, final class
ManageSyncStrategyCommand.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app, folder","depth":6,"role_description":"text"},{"role":"AXStaticText","text":".circleci, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".cursor, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".vscode, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".windsurf, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"Actions, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Component, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Acl, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activity, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Dtos, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Events, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AWS, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Cache, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Country, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Database, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Datadog, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DateTime, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Encoding, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Encryption, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ES, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Faker, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Gecko, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Gong, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Locks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Math, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Playlist, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Prophet, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Queue, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Router, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Saml2, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"SCIM, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Seeder, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Sentry, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Serializer, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Settings, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Slack, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Transcription, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Configuration, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Console, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activities, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Analytics, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Calendars, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Crm, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot, folder","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp, folder","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"Traits, folder","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php, class","depth":11,"role_description":"text"}]...
|
6646992787775520800
|
8404467957559831434
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder
.circleci, folder
.cursor, folder
.github
.sonarlint, folder
.vscode, folder
.windsurf, folder
app, sources root
Actions, folder
Component, folder
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder
FileSystem, folder
Gecko, folder
Gong, folder
GuzzleHttp, folder
KeyPoints, folder
Kiosk, folder
LanguageDetection, folder
LiveFeed, folder
Locks, folder
Math, folder
MediaPipeline, folder
MeetingBot, folder
MobileSettings, folder
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage, folder
Playlist, folder
Prophet, folder
ProphetAi, folder
ProsperWorks, folder
Queue, folder
Router, folder
Saml2, folder
SCIM, folder
Seeder, folder
Sentry, folder
Serializer, folder
Settings, folder
Sidekick, folder
Slack, folder
TeamInsights, folder
TimeMemoryMapper, folder
Transcription, folder
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration, folder
Console, folder
Commands, folder
Activities, folder
Analytics, folder
Calendars, folder
Crm, folder
Hubspot, folder
IntegrationApp, folder
Traits, folder
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php, class
BullhornSessionCommand.php, class
CheckActivityLoggableCommand.php, final class
CleanDuplicateFieldDataCommand.php, class
FullSyncOpportunityCommand.php, class
LogActivitiesCommand.php, final class
ManageSyncStrategyCommand.php, class...
|
76782
|
|
76788
|
NULL
|
0
|
2026-04-24T08:25:07.658513+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019107658_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder
.circleci, folder
.cursor, folder
.github
.sonarlint, folder
.vscode, folder
.windsurf, folder
app, sources root
Actions, folder
Component, folder
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder
FileSystem, folder
Gecko, folder
Gong, folder
GuzzleHttp, folder
KeyPoints, folder
Kiosk, folder
LanguageDetection, folder
LiveFeed, folder
Locks, folder
Math, folder
MediaPipeline, folder
MeetingBot, folder
MobileSettings, folder
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage, folder
Playlist, folder
Prophet, folder
ProphetAi, folder
ProsperWorks, folder
Queue, folder
Router, folder
Saml2, folder
SCIM, folder
Seeder, folder
Sentry, folder
Serializer, folder
Settings, folder
Sidekick, folder
Slack, folder
TeamInsights, folder
TimeMemoryMapper, folder
Transcription, folder
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.08510638,"height":0.025538707},"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.63796544,"top":0.12529927,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6476064,"top":0.123703115,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.6549202,"top":0.123703115,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.12210695,"width":0.34375,"height":0.87789303},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app, folder","depth":6,"role_description":"text"},{"role":"AXStaticText","text":".circleci, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".cursor, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".vscode, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".windsurf, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"Actions, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Component, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Acl, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activity, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Dtos, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Events, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AWS, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Cache, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Country, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Database, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Datadog, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DateTime, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Encoding, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Encryption, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ES, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Faker, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Gecko, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Gong, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Locks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Math, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Playlist, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Prophet, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Queue, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Router, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Saml2, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"SCIM, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Seeder, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Sentry, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Serializer, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Settings, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Slack, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Transcription, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"role_description":"text"}]...
|
6502072561878735239
|
8404466858121603978
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder
.circleci, folder
.cursor, folder
.github
.sonarlint, folder
.vscode, folder
.windsurf, folder
app, sources root
Actions, folder
Component, folder
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder
FileSystem, folder
Gecko, folder
Gong, folder
GuzzleHttp, folder
KeyPoints, folder
Kiosk, folder
LanguageDetection, folder
LiveFeed, folder
Locks, folder
Math, folder
MediaPipeline, folder
MeetingBot, folder
MobileSettings, folder
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage, folder
Playlist, folder
Prophet, folder
ProphetAi, folder
ProsperWorks, folder
Queue, folder
Router, folder
Saml2, folder
SCIM, folder
Seeder, folder
Sentry, folder
Serializer, folder
Settings, folder
Sidekick, folder
Slack, folder
TeamInsights, folder
TimeMemoryMapper, folder
Transcription, folder
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder...
|
76787
|
|
76264
|
1910
|
2
|
2026-04-24T07:38:51.075772+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016331075_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"bounds":{"left":0.8753325,"top":0.89944136,"width":0.100398935,"height":0.013567438},"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"bounds":{"left":0.8753325,"top":0.915403,"width":0.11037234,"height":0.027134877},"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.915403,"width":0.09507979,"height":0.027134877},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59541225,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6050532,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61236703,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.0,"width":0.34375,"height":1.0},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7506456211656557156
|
8404466858119637786
|
app_switch
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76265
|
1909
|
2
|
2026-04-24T07:38:52.745034+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016332745_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7506456211656557156
|
8404466858119637786
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76268
|
1910
|
4
|
2026-04-24T07:39:03.170910+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016343170_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"bounds":{"left":0.8753325,"top":0.89944136,"width":0.100398935,"height":0.013567438},"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"bounds":{"left":0.8753325,"top":0.915403,"width":0.11037234,"height":0.027134877},"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.915403,"width":0.09507979,"height":0.027134877},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59541225,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6050532,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61236703,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.0,"width":0.34375,"height":1.0},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7506456211656557156
|
8404466858119637786
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76269
|
1909
|
4
|
2026-04-24T07:39:03.246123+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016343246_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7506456211656557156
|
8404466858119637786
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76299
|
1909
|
20
|
2026-04-24T07:40:22.693414+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016422693_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7506456211656557156
|
8404466858119637786
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76300
|
1910
|
19
|
2026-04-24T07:40:23.371636+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016423371_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"bounds":{"left":0.8753325,"top":0.89944136,"width":0.100398935,"height":0.013567438},"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"bounds":{"left":0.8753325,"top":0.915403,"width":0.11037234,"height":0.027134877},"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.915403,"width":0.09507979,"height":0.027134877},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59541225,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6050532,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61236703,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.3200319,"width":0.34375,"height":0.6799681},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7506456211656557156
|
8404466858119637786
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76298
|
|
76308
|
1909
|
24
|
2026-04-24T07:40:39.882361+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016439882_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7506456211656557156
|
8404466858119637786
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76213
|
1907
|
27
|
2026-04-24T07:36:41.170360+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016201170_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Patch successfully applied
text/html
text/html
tex Patch successfully applied
text/html
text/html
text/html
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Patch successfully applied","depth":3,"value":"Patch successfully applied","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2008227989749799702
|
8404466858115443482
|
click
|
accessibility
|
NULL
|
Patch successfully applied
text/html
text/html
tex Patch successfully applied
text/html
text/html
text/html
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76211
|
|
76214
|
1908
|
29
|
2026-04-24T07:36:41.235053+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016201235_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Patch successfully applied
text/html
text/html
tex Patch successfully applied
text/html
text/html
text/html
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Patch successfully applied","depth":3,"bounds":{"left":0.24833776,"top":0.858739,"width":0.05418883,"height":0.013567438},"value":"Patch successfully applied","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.24833776,"top":0.858739,"width":0.05418883,"height":0.013567438},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59574467,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.60538566,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61269945,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2008227989749799702
|
8404466858115443482
|
click
|
accessibility
|
NULL
|
Patch successfully applied
text/html
text/html
tex Patch successfully applied
text/html
text/html
text/html
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76212
|
|
76215
|
1907
|
28
|
2026-04-24T07:36:42.905269+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016202905_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4138904741364594758
|
8404466858115443482
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76216
|
1908
|
30
|
2026-04-24T07:36:42.905269+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016202905_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59574467,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.60538566,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61269945,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4138904741364594758
|
8404466858115443482
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76219
|
1907
|
30
|
2026-04-24T07:36:51.853098+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016211853_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4138904741364594758
|
8404466858115443482
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76220
|
1908
|
32
|
2026-04-24T07:36:51.757629+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016211757_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59574467,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.60538566,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61269945,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4138904741364594758
|
8404466858115443482
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76295
|
1909
|
18
|
2026-04-24T07:40:17.148404+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016417148_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
SendReportNotGeneratedMailJobTes…edFormat
Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SendReportNotGeneratedMailJobTes…edFormat","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7289276460598085849
|
8404466858115443482
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
SendReportNotGeneratedMailJobTes…edFormat
Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76296
|
1910
|
17
|
2026-04-24T07:40:17.149839+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016417149_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
SendReportNotGeneratedMailJobTes…edFormat
Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"bounds":{"left":0.8753325,"top":0.89944136,"width":0.100398935,"height":0.013567438},"role_description":"text"},{"role":"AXTextField","text":"JY-20157 move user pilot tracking changes to separated PR","depth":3,"bounds":{"left":0.8753325,"top":0.915403,"width":0.11037234,"height":0.027134877},"value":"JY-20157 move user pilot tracking changes to separated PR","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.915403,"width":0.09507979,"height":0.027134877},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.78789896,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SendReportNotGeneratedMailJobTes…edFormat","depth":6,"bounds":{"left":0.8031915,"top":0.019952115,"width":0.11236702,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59541225,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6050532,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61236703,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.3200319,"width":0.34375,"height":0.6799681},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7289276460598085849
|
8404466858115443482
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 move user pilot trackin 2 files committed
JY-20157 move user pilot tracking changes to separated PR
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
SendReportNotGeneratedMailJobTes…edFormat
Run 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
Debug 'SendReportNotGeneratedMailJobTest.testUniqueIdReturnsExpectedFormat'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76294
|
|
76321
|
1910
|
30
|
2026-04-24T07:41:15.066005+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016475066_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 add test coverage
text/ 2 files committed
JY-20157 add test coverage
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"role_description":"text"},{"role":"AXTextField","text":"JY-20157 add test coverage","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"value":"JY-20157 add test coverage","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.05817819,"height":0.013567438},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59541225,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6050532,"top":0.3216281,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.61236703,"top":0.3216281,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.070231445,"width":0.34375,"height":0.92976856},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
105150503854657824
|
8404466858115443482
|
click
|
accessibility
|
NULL
|
2 files committed
JY-20157 add test coverage
text/ 2 files committed
JY-20157 add test coverage
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|