setMessage('success message'); $notification->setTitle('PHPFlasher'); $notification->setType('success'); $envelopes[] = new Envelope($notification, [ new CreatedAtStamp(new \DateTimeImmutable('2023-02-05 16:22:50')), new IdStamp('1111'), ]); $notification = new Notification(); $notification->setMessage('warning message'); $notification->setTitle('yoeunes/toastr'); $notification->setType('warning'); $envelopes[] = new Envelope($notification, [ new CreatedAtStamp(new \DateTimeImmutable('2023-02-06 16:22:50')), new IdStamp('2222'), ]); $resourceManager = $this->createMock(ResourceManagerInterface::class); $resourceManager->method('populateResponse')->willReturnArgument(0); $storageManager = $this->createMock(StorageManagerInterface::class); $eventDispatcher = $this->createMock(EventDispatcherInterface::class); $responseManager = new ResponseManager($resourceManager, $storageManager, $eventDispatcher); $scriptTagWithNonce = ''; $livewireListener = $this->getLivewireListenerScript(); $response = << (function(window, document) { const merge = (first, second) => { if (Array.isArray(first) && Array.isArray(second)) { return [...first, ...second.filter(item => !first.includes(item))]; } if (typeof first === 'object' && typeof second === 'object') { for (const [key, value] of Object.entries(second)) { first[key] = key in first ? { ...first[key], ...value } : value; } return first; } return undefined; }; const mergeOptions = (...options) => { const result = {}; options.forEach(option => { Object.entries(option).forEach(([key, value]) => { result[key] = key in result ? merge(result[key], value) : value; }); }); return result; }; const renderCallback = (options) => { if(!window.flasher) { throw new Error('Flasher is not loaded'); } window.flasher.render(options); }; const render = (options) => { if (options instanceof Event) { options = options.detail; } if (['interactive', 'complete'].includes(document.readyState)) { renderCallback(options); } else { document.addEventListener('DOMContentLoaded', () => renderCallback(options)); } }; const addScriptAndRender = (options) => { const mainScript = ""; if (window.flasher || !mainScript || document.querySelector('script[src="' + mainScript + '"]')) { render(options); } else { const tag = document.createElement('script'); tag.src = mainScript; tag.type = 'text/javascript'; {$scriptTagWithNonce} tag.onload = () => render(options); document.head.appendChild(tag); } }; const addRenderListener = () => { if (1 === document.querySelectorAll('script.flasher-js').length) { document.addEventListener('flasher:render', render); document.addEventListener('turbo:before-cache', () => { document.querySelectorAll('.fl-wrapper').forEach(el => el.remove()); }); } {$livewireListener} }; const options = []; options.push({"envelopes":[],"scripts":[],"styles":[],"options":[],"context":[]}); /** {--FLASHER_REPLACE_ME--} **/ addScriptAndRender(mergeOptions(...options)); addRenderListener(); })(window, document); JAVASCRIPT; $this->assertSame($response, $responseManager->render('html')); } public function testItThrowsExceptionIfPresenterNotFound(): void { $this->expectException(PresenterNotFoundException::class); $this->expectExceptionMessage('Presenter "xml" not found, did you forget to register it? Available presenters: [html, json, array]'); $resourceManager = $this->createMock(ResourceManagerInterface::class); $resourceManager->method('populateResponse')->willReturnArgument(0); $storageManager = $this->createMock(StorageManagerInterface::class); $eventDispatcher = $this->createMock(EventDispatcherInterface::class); $responseManager = new ResponseManager($resourceManager, $storageManager, $eventDispatcher); $responseManager->render('xml'); } /** * Generate the script for Livewire event handling. */ private function getLivewireListenerScript(): string { if (!class_exists(LivewireManager::class)) { return ''; } return << { document.querySelectorAll('.fl-wrapper').forEach(el => el.remove()); }); JAVASCRIPT; } public function testAddPresenterWithCallable(): void { $resourceManager = $this->createMock(ResourceManagerInterface::class); $resourceManager->method('populateResponse')->willReturnArgument(0); $storageManager = $this->createMock(StorageManagerInterface::class); $eventDispatcher = $this->createMock(EventDispatcherInterface::class); $responseManager = new ResponseManager($resourceManager, $storageManager, $eventDispatcher); $customPresenter = new \Flasher\Prime\Response\Presenter\ArrayPresenter(); $responseManager->addPresenter('custom', fn () => $customPresenter); $result = $responseManager->render('custom'); $this->assertIsArray($result); } public function testAddPresenterWithCallableReturningInvalidTypeThrowsException(): void { $resourceManager = $this->createMock(ResourceManagerInterface::class); $resourceManager->method('populateResponse')->willReturnArgument(0); $storageManager = $this->createMock(StorageManagerInterface::class); $eventDispatcher = $this->createMock(EventDispatcherInterface::class); $responseManager = new ResponseManager($resourceManager, $storageManager, $eventDispatcher); $responseManager->addPresenter('invalid', fn () => 'not a presenter'); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Presenter callable for "invalid" must return an instance of'); $responseManager->render('invalid'); } public function testAddPresenterWithDirectInstance(): void { $resourceManager = $this->createMock(ResourceManagerInterface::class); $resourceManager->method('populateResponse')->willReturnArgument(0); $storageManager = $this->createMock(StorageManagerInterface::class); $eventDispatcher = $this->createMock(EventDispatcherInterface::class); $responseManager = new ResponseManager($resourceManager, $storageManager, $eventDispatcher); $customPresenter = new \Flasher\Prime\Response\Presenter\ArrayPresenter(); $responseManager->addPresenter('direct', $customPresenter); $result = $responseManager->render('direct'); $this->assertIsArray($result); } }