Initial commit: CloudOps infrastructure platform

This commit is contained in:
root
2026-04-09 19:58:57 +02:00
commit 1166a52f26
7762 changed files with 839452 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Controller\Api;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use PHPUnit\Framework\Assert;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
final class FocusApiControllerTest extends MauticMysqlTestCase
{
/**
* @var array<string,mixed>
*/
private array $testPayload = [
'name' => 'test',
'type' => 'notice',
'website' => 'http://',
'style' => 'bar',
'htmlMode' => 1,
'html' => '<div><strong style="color:red">html mode enabled</strong></div>',
'properties' => [
'bar' => [
'allow_hide' => 1,
'sticky' => 1,
'size' => 'large',
'placement' => 'top',
],
'modal' => [
'placement' => 'top',
],
'notification' => [
'placement' => 'top_left',
],
'animate' => 1,
'link_activation' => 1,
'colors' => [
'primary' => '27184e',
],
'content' => [
'headline' => '',
'font' => 'Arial, Helvetica, sans-serif',
],
'when' => 'immediately',
'frequency' => 'everypage',
'stop_after_conversion' => 1,
],
];
public function testFocusApiNew(): void
{
// Create a focus item.
$this->client->request(Request::METHOD_POST, '/api/focus/new', $this->testPayload);
$response = $this->client->getResponse();
$this->assertEquals(Response::HTTP_CREATED, $response->getStatusCode(), $response->getContent());
$createdItem = json_decode($response->getContent(), true)['focus'];
Assert::assertNotEmpty($createdItem['id'], $response->getContent());
Assert::assertSame($this->testPayload['name'], $createdItem['name'], $response->getContent());
}
}

View File

@@ -0,0 +1,131 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Controller;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\PageBundle\Entity\Hit;
use MauticPlugin\MauticFocusBundle\Entity\Focus;
use MauticPlugin\MauticFocusBundle\Entity\Stat;
use MauticPlugin\MauticFocusBundle\Model\FocusModel;
use Symfony\Component\HttpFoundation\Request;
class FocusAjaxControllerFunctionalTest extends MauticMysqlTestCase
{
public function testViewsCount(): void
{
/** @var FocusModel $focusModel */
$focusModel = static::getContainer()->get('mautic.focus.model.focus');
$focus = $this->createFocus('popup');
$focusModel->saveEntity($focus);
$leads = [
$this->createLead(),
$this->createLead(),
];
$focusModel->addStat($focus, Stat::TYPE_NOTIFICATION, null, $leads[0]);
$focusModel->addStat($focus, Stat::TYPE_NOTIFICATION, null, $leads[0]);
$focusModel->addStat($focus, Stat::TYPE_NOTIFICATION, null, $leads[1]);
$this->client->xmlHttpRequest(Request::METHOD_GET, "/s/ajax?action=plugin:focus:getViewsCount&focusId={$focus->getId()}");
$response = $this->client->getResponse();
$this->assertTrue($response->isOk());
$this->assertSame([
'success' => 1,
'views' => 3,
'uniqueViews' => 2,
], json_decode($response->getContent(), true));
}
public function testClickThroughCount(): void
{
/** @var FocusModel $focusModel */
$focusModel = static::getContainer()->get('mautic.focus.model.focus');
$focus = $this->createFocus('popup');
$focusModel->saveEntity($focus);
$lead1 = $this->createLead();
$lead2 = $this->createLead();
$focusModel->addStat($focus, Stat::TYPE_CLICK, $this->createHit($lead1), $lead1);
$focusModel->addStat($focus, Stat::TYPE_CLICK, $this->createHit($lead1), $lead1);
$focusModel->addStat($focus, Stat::TYPE_CLICK, $this->createHit($lead2), $lead2);
$this->client->xmlHttpRequest(Request::METHOD_GET, "/s/ajax?action=plugin:focus:getClickThroughCount&focusId={$focus->getId()}");
$response = $this->client->getResponse();
$this->assertTrue($response->isOk());
$this->assertSame([
'success' => 1,
'clickThrough' => 2,
], json_decode($response->getContent(), true));
}
private function createHit(Lead $lead): Hit
{
$hit = new Hit();
$hit->setLead($lead);
return $hit;
}
private function createFocus(string $name): Focus
{
$focus = new Focus();
$focus->setName($name);
$focus->setType('link');
$focus->setStyle('modal');
$focus->setProperties([
'bar' => [
'allow_hide' => 1,
'push_page' => 1,
'sticky' => 1,
'size' => 'large',
'placement' => 'top',
],
'modal' => [
'placement' => 'top',
],
'notification' => [
'placement' => 'top_left',
],
'page' => [],
'animate' => 0,
'link_activation' => 1,
'colors' => [
'primary' => '4e5d9d',
'text' => '000000',
'button' => 'fdb933',
'button_text' => 'ffffff',
],
'content' => [
'headline' => null,
'tagline' => null,
'link_text' => null,
'link_url' => null,
'link_new_window' => 1,
'font' => 'Arial, Helvetica, sans-serif',
'css' => null,
],
'when' => 'immediately',
'timeout' => null,
'frequency' => 'everypage',
'stop_after_conversion' => 1,
]);
return $focus;
}
private function createLead(): Lead
{
$lead = new Lead();
$lead->setFirstname('Contact');
$lead->setEmail('test@test.com');
$this->em->persist($lead);
$this->em->flush();
return $lead;
}
}

View File

@@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Controller;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use MauticPlugin\MauticFocusBundle\Entity\Focus;
use MauticPlugin\MauticFocusBundle\Model\FocusModel;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
final class FocusControllerTest extends MauticMysqlTestCase
{
public function testIndexActionIsSuccessful(): void
{
$this->client->request(Request::METHOD_GET, '/s/focus');
$response = $this->client->getResponse();
$this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
}
public function testNewActionIsSuccessful(): void
{
$this->client->request(Request::METHOD_GET, '/s/focus/new');
$response = $this->client->getResponse();
$this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
}
public function testRecentActivityFeedOnFocusDetailsPage(): void
{
$focus = new Focus();
$focus->setName('Test Focus');
$focus->setType('link');
$focus->setStyle('modal');
$focus->setProperties([
'bar' => [
'allow_hide' => 1,
'push_page' => 1,
'sticky' => 1,
'size' => 'large',
'placement' => 'top',
],
'modal' => [
'placement' => 'top',
],
'notification' => [
'placement' => 'top_left',
],
'page' => [],
'animate' => 0,
'link_activation' => 1,
'colors' => [
'primary' => '4e5d9d',
'text' => '000000',
'button' => 'fdb933',
'button_text' => 'ffffff',
],
'content' => [
'headline' => null,
'tagline' => null,
'link_text' => null,
'link_url' => null,
'link_new_window' => 1,
'font' => 'Arial, Helvetica, sans-serif',
'css' => null,
],
'when' => 'immediately',
'timeout' => null,
'frequency' => 'everypage',
'stop_after_conversion' => 1,
]);
/** @var FocusModel $focusModel */
$focusModel = static::getContainer()->get('mautic.focus.model.focus');
$focusModel->saveEntity($focus);
$this->em->clear();
$crawler = $this->client->request(Request::METHOD_GET, '/s/focus/edit/'.$focus->getId());
$this->assertResponseIsSuccessful();
$form = $crawler->selectButton('focus_buttons_apply')->form();
$form['focus[isPublished]']->setValue('0');
$this->client->submit($form);
$crawler = $this->client->request(Request::METHOD_GET, '/s/focus/view/'.$focus->getId());
$this->assertResponseIsSuccessful();
$translator = self::getContainer()->get('translator');
$this->assertStringContainsString($translator->trans('mautic.core.recent.activity'), $this->client->getResponse()->getContent());
$this->assertCount(2, $crawler->filterXPath('//ul[contains(@class, "media-list-feed")]/li'));
}
}

View File

@@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Controller;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use MauticPlugin\MauticFocusBundle\Entity\Focus;
use MauticPlugin\MauticFocusBundle\Model\FocusModel;
use Symfony\Component\HttpFoundation\Request;
class FocusPublicControllerFunctionalTest extends MauticMysqlTestCase
{
public function testGenerateFocusItemScript(): void
{
/** @var FocusModel $focusModel */
$focusModel = static::getContainer()->get('mautic.focus.model.focus');
$focus = $this->createFocus('popup');
$focusModel->saveEntity($focus);
$this->client->request(Request::METHOD_GET, "/focus/{$focus->getId()}.js");
$response = $this->client->getResponse();
$this->assertTrue($response->isOk());
$this->assertNotEmpty($response->getContent());
}
public function testInactiveFocusItemScript(): void
{
/** @var FocusModel $focusModel */
$focusModel = static::getContainer()->get('mautic.focus.model.focus');
$focus = $this->createFocus('popup');
$focus->setIsPublished(false);
$focusModel->saveEntity($focus);
$this->client->request(Request::METHOD_GET, "/focus/{$focus->getId()}.js");
$response = $this->client->getResponse();
$this->assertTrue($response->isNotFound());
$this->assertEmpty($response->getContent());
}
private function createFocus(string $name): Focus
{
$focus = new Focus();
$focus->setName($name);
$focus->setType('link');
$focus->setStyle('modal');
$focus->setProperties([
'bar' => [
'allow_hide' => 1,
'push_page' => 1,
'sticky' => 1,
'size' => 'large',
'placement' => 'top',
],
'modal' => [
'placement' => 'top',
],
'notification' => [
'placement' => 'top_left',
],
'page' => [],
'animate' => 0,
'link_activation' => 1,
'colors' => [
'primary' => '4e5d9d',
'text' => '000000',
'button' => 'fdb933',
'button_text' => 'ffffff',
],
'content' => [
'headline' => null,
'tagline' => null,
'link_text' => null,
'link_url' => null,
'link_new_window' => 1,
'font' => 'Arial, Helvetica, sans-serif',
'css' => null,
],
'when' => 'immediately',
'timeout' => null,
'frequency' => 'everypage',
'stop_after_conversion' => 1,
]);
return $focus;
}
}

View File

@@ -0,0 +1,125 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Entity;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\PageBundle\Entity\Hit;
use MauticPlugin\MauticFocusBundle\Entity\Focus;
use MauticPlugin\MauticFocusBundle\Entity\Stat;
use MauticPlugin\MauticFocusBundle\Model\FocusModel;
class StatRepositoryFunctionalTest extends MauticMysqlTestCase
{
private FocusModel $focusModel;
protected function setUp(): void
{
parent::setUp();
$this->focusModel = static::$kernel->getContainer()->get('mautic.focus.model.focus');
$this->setTestsData($this->createLead(), $this->focusModel);
}
public function testGetStatsViewByLead(): void
{
$this->assertCount(5, $this->focusModel->getStatRepository()->getStatsViewByLead());
}
public function testGetStatsClickByLead(): void
{
$this->assertCount(2, $this->focusModel->getStatRepository()->getStatsClickByLead());
}
private function createLead(): Lead
{
$lead = new Lead();
$lead->setFirstname('Contact');
$lead->setEmail('test@test.com');
$this->em->persist($lead);
$this->em->flush();
return $lead;
}
private function setTestsData(Lead $lead, FocusModel $focusModel): void
{
$focusPopupA = $this->createFocus('popup focus A');
$focusPopupB = $this->createFocus('popup focus B');
$focusPopupC = $this->createFocus('popup focus C');
$focusBarA = $this->createFocus('bar focus A');
$focusBarB = $this->createFocus('bar focus B');
$this->focusModel->saveEntity($focusPopupA);
$this->focusModel->saveEntity($focusPopupB);
$this->focusModel->saveEntity($focusPopupC);
$this->focusModel->saveEntity($focusBarA);
$this->focusModel->saveEntity($focusBarB);
$hitPopupA = new Hit();
$hitPopupA->setLead($lead);
$hitBarB = new Hit();
$hitBarB->setLead($lead);
$this->focusModel->addStat($focusPopupA, Stat::TYPE_NOTIFICATION, null, $lead);
$this->focusModel->addStat($focusPopupB, Stat::TYPE_NOTIFICATION, null, $lead);
$this->focusModel->addStat($focusPopupB, Stat::TYPE_CLICK, $hitPopupA, $lead);
$this->focusModel->addStat($focusPopupC, Stat::TYPE_NOTIFICATION, null, $lead);
$this->focusModel->addStat($focusBarA, Stat::TYPE_NOTIFICATION, null, $lead);
$this->focusModel->addStat($focusBarA, Stat::TYPE_CLICK, $hitBarB, $lead);
$this->focusModel->addStat($focusBarB, Stat::TYPE_NOTIFICATION, null, $lead);
}
private function createFocus(string $name): Focus
{
$focus = new Focus();
$focus->setName($name);
$focus->setType('link');
$focus->setStyle('modal');
$focus->setProperties([
'bar' => [
'allow_hide' => 1,
'push_page' => 1,
'sticky' => 1,
'size' => 'large',
'placement' => 'top',
],
'modal' => [
'placement' => 'top',
],
'notification' => [
'placement' => 'top_left',
],
'page' => [],
'animate' => 0,
'link_activation' => 1,
'colors' => [
'primary' => '4e5d9d',
'text' => '000000',
'button' => 'fdb933',
'button_text' => 'ffffff',
],
'content' => [
'headline' => null,
'tagline' => null,
'link_text' => null,
'link_url' => null,
'link_new_window' => 1,
'font' => 'Arial, Helvetica, sans-serif',
'css' => null,
],
'when' => 'immediately',
'timeout' => null,
'frequency' => 'everypage',
'stop_after_conversion' => 1,
]);
return $focus;
}
}

View File

@@ -0,0 +1,143 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\EventListener;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\PageBundle\Entity\Hit;
use MauticPlugin\MauticFocusBundle\Entity\Focus;
use MauticPlugin\MauticFocusBundle\Entity\Stat;
use MauticPlugin\MauticFocusBundle\Model\FocusModel;
class LeadSubscriberFunctionalTest extends MauticMysqlTestCase
{
private Lead $lead;
private FocusModel $focusModel;
protected function setUp(): void
{
parent::setUp();
$this->focusModel = static::getContainer()->get('mautic.focus.model.focus');
$this->lead = $this->createLead();
$this->setTestsData($this->lead, $this->focusModel);
}
public function testSearchPhraseInNameFocusStat(): void
{
$this->assertCount(3, $this->searchPhrase('bar', $this->lead, $this->focusModel));
$this->assertCount(4, $this->searchPhrase('popup', $this->lead, $this->focusModel));
$this->assertCount(2, $this->searchPhrase('popup focus B', $this->lead, $this->focusModel));
}
public function testSearchPhraseInTypeFocusStat(): void
{
$this->assertCount(2, $this->searchPhrase('click', $this->lead, $this->focusModel));
$this->assertCount(5, $this->searchPhrase('view', $this->lead, $this->focusModel));
}
/**
* @return array<string, mixed>
*/
private function searchPhrase(string $phrase, Lead $lead, FocusModel $focusModel): array
{
$searchViewStats = $focusModel->getStatRepository()->getStatsViewByLead((int) $lead->getId(), ['search'=>$phrase]);
$searchClickStats = $focusModel->getStatRepository()->getStatsClickByLead((int) $lead->getId(), ['search'=>$phrase]);
return array_merge($searchViewStats, $searchClickStats);
}
private function setTestsData(Lead $lead, FocusModel $focusModel): void
{
$focusPopupA = $this->createFocus('popup focus A');
$focusPopupB = $this->createFocus('popup focus B');
$focusPopupC = $this->createFocus('popup focus C');
$focusBarA = $this->createFocus('bar focus A');
$focusBarB = $this->createFocus('bar focus B');
$this->focusModel->saveEntity($focusPopupA);
$this->focusModel->saveEntity($focusPopupB);
$this->focusModel->saveEntity($focusPopupC);
$this->focusModel->saveEntity($focusBarA);
$this->focusModel->saveEntity($focusBarB);
$hitPopupA = new Hit();
$hitPopupA->setLead($lead);
$hitBarB = new Hit();
$hitBarB->setLead($lead);
$this->focusModel->addStat($focusPopupA, Stat::TYPE_NOTIFICATION, null, $lead);
$this->focusModel->addStat($focusPopupB, Stat::TYPE_NOTIFICATION, null, $lead);
$this->focusModel->addStat($focusPopupB, Stat::TYPE_CLICK, $hitPopupA, $lead);
$this->focusModel->addStat($focusPopupC, Stat::TYPE_NOTIFICATION, null, $lead);
$this->focusModel->addStat($focusBarA, Stat::TYPE_NOTIFICATION, null, $lead);
$this->focusModel->addStat($focusBarA, Stat::TYPE_CLICK, $hitBarB, $lead);
$this->focusModel->addStat($focusBarB, Stat::TYPE_NOTIFICATION, null, $lead);
}
private function createFocus(string $name): Focus
{
$focus = new Focus();
$focus->setName($name);
$focus->setType('link');
$focus->setStyle('modal');
$focus->setProperties([
'bar' => [
'allow_hide' => 1,
'push_page' => 1,
'sticky' => 1,
'size' => 'large',
'placement' => 'top',
],
'modal' => [
'placement' => 'top',
],
'notification' => [
'placement' => 'top_left',
],
'page' => [],
'animate' => 0,
'link_activation' => 1,
'colors' => [
'primary' => '4e5d9d',
'text' => '000000',
'button' => 'fdb933',
'button_text' => 'ffffff',
],
'content' => [
'headline' => null,
'tagline' => null,
'link_text' => null,
'link_url' => null,
'link_new_window' => 1,
'font' => 'Arial, Helvetica, sans-serif',
'css' => null,
],
'when' => 'immediately',
'timeout' => null,
'frequency' => 'everypage',
'stop_after_conversion' => 1,
]);
return $focus;
}
private function createLead(): Lead
{
$lead = new Lead();
$lead->setFirstname('Contact');
$lead->setEmail('test@test.com');
$this->em->persist($lead);
$this->em->flush();
return $lead;
}
}

View File

@@ -0,0 +1,234 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\EventListener;
use Mautic\CoreBundle\Tests\CommonMocks;
use Mautic\CoreBundle\Translation\Translator;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Event\LeadTimelineEvent;
use Mautic\LeadBundle\LeadEvents;
use MauticPlugin\MauticFocusBundle\Entity\Stat;
use MauticPlugin\MauticFocusBundle\Entity\StatRepository;
use MauticPlugin\MauticFocusBundle\EventListener\LeadSubscriber;
use MauticPlugin\MauticFocusBundle\FocusEventTypes;
use MauticPlugin\MauticFocusBundle\Model\FocusModel;
use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Routing\RouterInterface;
class LeadSubscriberTest extends CommonMocks
{
/**
* @var Translator|MockObject
*/
private MockObject $translator;
/**
* @var RouterInterface|MockObject
*/
private MockObject $router;
/**
* @var FocusModel|(FocusModel&MockObject)|MockObject
*/
private MockObject $focusModel;
/**
* @var StatRepository|(StatRepository&MockObject)|MockObject
*/
private MockObject $statRepository;
/**
* @var string
*/
private const EVENT_TYPE_VIEW_NAME = 'Focus view';
/**
* @var string
*/
private const EVENT_TYPE_CLICK_NAME = 'Focus click';
/**
* @var string
*/
private const FOCUS_NAME = 'test Focus Item';
protected function setUp(): void
{
$this->translator = $this->createMock(Translator::class);
$this->router = $this->createMock(RouterInterface::class);
$this->focusModel = $this->createMock(FocusModel::class);
$this->statRepository = $this->createMock(StatRepository::class);
$matcher = $this->any();
$this->translator->expects($matcher)
->method('trans')->willReturnCallback(function (...$parameters) use ($matcher) {
if (1 === $matcher->numberOfInvocations()) {
$this->assertSame('mautic.focus.event.view', $parameters[0]);
return self::EVENT_TYPE_VIEW_NAME;
}
if (2 === $matcher->numberOfInvocations()) {
$this->assertSame('mautic.focus.event.click', $parameters[0]);
return self::EVENT_TYPE_CLICK_NAME;
}
});
}
/**
* Make sure that on timeline entry is created for a lead
* that was displayed Focus Item.
*/
public function testShowFocusItem(): void
{
$lead = $this->getLead();
$date = new \DateTime();
$this->mockFocusModelGetStatsByLead(Stat::TYPE_NOTIFICATION, self::FOCUS_NAME, 'getStatsViewByLead', $date);
$timelineEvent = $this->getTimelineEvent(
FocusEventTypes::FOCUS_ON_VIEW, self::EVENT_TYPE_VIEW_NAME, self::FOCUS_NAME, $date, $lead
);
$leadEvent = new LeadTimelineEvent($lead);
$subscriber = new LeadSubscriber(
$this->translator,
$this->router,
$this->focusModel
);
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber($subscriber);
$dispatcher->dispatch($leadEvent, LeadEvents::TIMELINE_ON_GENERATE);
$this->assertSame([$timelineEvent], $leadEvent->getEvents());
}
public function testShowFocusItemWhenNoLead(): void
{
$date = new \DateTime();
$this->mockFocusModelGetStatsByLead(Stat::TYPE_NOTIFICATION, self::FOCUS_NAME, 'getStatsViewByLead', $date);
$timelineEvent = $this->getTimelineEvent(
FocusEventTypes::FOCUS_ON_VIEW, self::EVENT_TYPE_VIEW_NAME, self::FOCUS_NAME, $date
);
$leadEvent = new LeadTimelineEvent();
$subscriber = new LeadSubscriber(
$this->translator,
$this->router,
$this->focusModel
);
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber($subscriber);
$dispatcher->dispatch($leadEvent, LeadEvents::TIMELINE_ON_GENERATE);
$this->assertSame([$timelineEvent], $leadEvent->getEvents());
}
/**
* Make sure that on timeline entry is created for a lead
* that was clicked Focus Item.
*/
public function testClickFocusItem(): void
{
$lead = $this->getLead();
$date = new \DateTime();
$this->mockFocusModelGetStatsByLead(Stat::TYPE_CLICK, self::FOCUS_NAME, 'getStatsClickByLead', $date);
$timelineEvent = $this->getTimelineEvent(
FocusEventTypes::FOCUS_ON_CLICK, self::EVENT_TYPE_CLICK_NAME, self::FOCUS_NAME, $date, $lead
);
$leadEvent = new LeadTimelineEvent($lead);
$subscriber = new LeadSubscriber(
$this->translator,
$this->router,
$this->focusModel
);
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber($subscriber);
$dispatcher->dispatch($leadEvent, LeadEvents::TIMELINE_ON_GENERATE);
$this->assertSame([$timelineEvent], $leadEvent->getEvents());
}
public function testClickFocusItemWhenNoLead(): void
{
$date = new \DateTime();
$this->mockFocusModelGetStatsByLead(Stat::TYPE_CLICK, self::FOCUS_NAME, 'getStatsClickByLead', $date);
$timelineEvent = $this->getTimelineEvent(
FocusEventTypes::FOCUS_ON_CLICK, self::EVENT_TYPE_CLICK_NAME, self::FOCUS_NAME, $date
);
$leadEvent = new LeadTimelineEvent();
$subscriber = new LeadSubscriber(
$this->translator,
$this->router,
$this->focusModel
);
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber($subscriber);
$dispatcher->dispatch($leadEvent, LeadEvents::TIMELINE_ON_GENERATE);
$this->assertSame([$timelineEvent], $leadEvent->getEvents());
}
private function mockFocusModelGetStatsByLead(string $statType, string $focusName, string $method, \DateTime $date): void
{
$stats = [
'results'=> [
[
'id' => 1,
'type' => $statType,
'date_added' => $date,
'focus_id' => 1,
'focus_name' => $focusName,
],
],
'total'=> 1,
];
$this->statRepository->method($method)->willReturn($stats);
$this->focusModel->method('getStatRepository')->willReturn($this->statRepository);
}
private function getLead(): Lead
{
$lead = new Lead();
$lead->setId(1);
return $lead;
}
/**
* @return array<string, mixed>
*/
private function getTimelineEvent(string $eventType, string $eventTypeName, string $focusName, \DateTime $date, ?Lead $lead=null): array
{
$leadEventLogId = 1;
return [
'event' => $eventType,
'eventId' => $eventType.'.'.$leadEventLogId,
'eventLabel' => [
'label' => $focusName,
'href' => '',
],
'eventType' => $eventTypeName,
'timestamp' => $date,
'icon' => 'ri-search-line',
'contactId' => $lead?->getId(),
];
}
}

View File

@@ -0,0 +1,180 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\EventListener;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\PageBundle\Entity\Redirect;
use Mautic\PageBundle\Entity\Trackable;
use Mautic\ReportBundle\Entity\Report;
use MauticPlugin\MauticFocusBundle\Entity\Focus;
use MauticPlugin\MauticFocusBundle\Entity\Stat;
use MauticPlugin\MauticFocusBundle\EventListener\ReportSubscriber;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\HttpFoundation\Request;
final class ReportSubscriberFunctionalTest extends MauticMysqlTestCase
{
protected function setUp(): void
{
parent::setUp();
}
public function testGenerateFocusItemReportWithAllAvailableColumns(): void
{
$this->fillDatabase();
$report = new Report();
$report->setName('Focus Stats Report');
$report->setSource(ReportSubscriber::CONTEXT_FOCUS_STATS);
$report->setColumns([ReportSubscriber::PREFIX_FOCUS.'.name', ReportSubscriber::PREFIX_FOCUS.'.description', ReportSubscriber::PREFIX_FOCUS.'.focus_type', ReportSubscriber::PREFIX_FOCUS.'.style', ReportSubscriber::PREFIX_STATS.'.type', ReportSubscriber::PREFIX_TRACKABLES.'.hits', ReportSubscriber::PREFIX_TRACKABLES.'.unique_hits', ReportSubscriber::PREFIX_REDIRECTS.'.url',
]);
$this->em->persist($report);
$this->em->flush();
$crawler = $this->client->request(Request::METHOD_GET, "/s/reports/view/{$report->getId()}");
$this->assertTrue($this->client->getResponse()->isOk());
// get table with id=reportTable
$crawlerTable = $crawler->filter('#reportTable');
// remove first line of table (column names)
$table = array_slice($this->domTableToArray($crawlerTable), 1);
// remove last line of table (unnecessary part generated by js)
array_pop($table);
$this->assertSame([
['1', 'FocusItem1', 'doesAbc', 'link', 'modal', 'click', '1', '1', 'http://example1.com'],
['2', 'FocusItem1', 'doesAbc', 'link', 'modal', 'view', '3', '2', 'http://example1.com'],
['3', 'FocusItem2', 'doesAbcd', 'link', 'modal', 'click', '1', '1', 'http://example2.com'],
['4', 'FocusItem2', 'doesAbcd', 'link', 'modal', 'view', '1', '1', 'http://example2.com'],
], $table);
}
public function testGenerateFocusItemReportFocusLeadsColumns(): void
{
$this->fillDatabase();
$report = new Report();
$report->setName('Focus Leads Report');
$report->setSource(ReportSubscriber::CONTEXT_FOCUS_LEADS);
$report->setColumns(
[
ReportSubscriber::PREFIX_LEADS.'.email',
ReportSubscriber::PREFIX_FOCUS.'.name',
ReportSubscriber::PREFIX_FOCUS.'.description',
ReportSubscriber::PREFIX_FOCUS.'.focus_type',
ReportSubscriber::PREFIX_FOCUS.'.style',
ReportSubscriber::PREFIX_STATS.'.type',
ReportSubscriber::PREFIX_TRACKABLES.'.hits',
ReportSubscriber::PREFIX_REDIRECTS.'.url',
]
);
$this->em->persist($report);
$this->em->flush();
$crawler = $this->client->request(Request::METHOD_GET, "/s/reports/view/{$report->getId()}");
$this->assertTrue($this->client->getResponse()->isOk());
// get table with id=reportTable
$crawlerTable = $crawler->filter('#reportTable');
// remove first line of table (column names)
$table = array_slice($this->domTableToArray($crawlerTable), 1);
// remove last line of table (unnecessary part generated by js)
array_pop($table);
$this->assertSame([
['1', 'lead.1@example.com', 'FocusItem1', 'doesAbc', 'link', 'modal', 'click', '1', 'http://example1.com'],
['2', 'lead.1@example.com', 'FocusItem1', 'doesAbc', 'link', 'modal', 'view', '2', 'http://example1.com'],
['3', 'lead.2@example.com', 'FocusItem1', 'doesAbc', 'link', 'modal', 'view', '1', 'http://example1.com'],
['4', 'lead.2@example.com', 'FocusItem2', 'doesAbcd', 'link', 'modal', 'click', '1', 'http://example2.com'],
['5', 'lead.2@example.com', 'FocusItem2', 'doesAbcd', 'link', 'modal', 'view', '1', 'http://example2.com'],
], $table);
}
private function fillDatabase(): void
{
$lead1= $this->createContact('lead.1@example.com');
$lead2= $this->createContact('lead.2@example.com');
$focus1 = $this->createFocusItem('FocusItem1', 'doesAbc', 'link', 'modal');
$focus2 = $this->createFocusItem('FocusItem2', 'doesAbcd', 'link', 'modal');
$focus3 = $this->createFocusItem('FocusItem3', 'doesAbcde', 'link', 'modal');
$this->em->flush();
$date = new \DateTime();
$this->createFocusStats('click', $focus1, $lead1, $date);
$this->createFocusStats('click', $focus2, $lead2, $date);
$this->createFocusStats('view', $focus1, $lead1, $date);
$this->createFocusStats('view', $focus1, $lead1, $date);
$this->createFocusStats('view', $focus1, $lead2, $date);
$this->createFocusStats('view', $focus2, $lead2, $date);
/** @var int $focusId1 */
$focusId1 = $focus1->getId();
/** @var int $focusId2 */
$focusId2 = $focus2->getId();
$this->createTrackableAndRedirects('http://example1.com', $focusId1, 1, 1);
$this->createTrackableAndRedirects('http://example2.com', $focusId2, 1, 1);
$this->createTrackableAndRedirects('http://example2.com', $focusId2);
$this->em->flush();
$this->em->clear();
}
private function createContact(string $email): Lead
{
$contact = new Lead();
$contact->setEmail($email);
$this->em->persist($contact);
return $contact;
}
private function createFocusItem(string $name, string $description, string $focusType, string $style): Focus
{
$focus = new Focus();
$focus->setName($name);
$focus->setDescription($description);
$focus->setType($focusType);
$focus->setStyle($style);
$this->em->persist($focus);
return $focus;
}
private function createFocusStats(string $type, Focus $focus, Lead $lead, \DateTime $dateAdded): void
{
$focusStats = new Stat();
$focusStats->setType($type);
$focusStats->setFocus($focus);
$focusStats->setLead($lead);
$focusStats->setDateAdded($dateAdded);
$this->em->persist($focusStats);
}
private function createTrackableAndRedirects(string $url, int $channelId, int $hits = 0, int $uniqueHits = 0): void
{
$redirect = new Redirect();
$redirect->setRedirectId(uniqid());
$redirect->setUrl($url);
$redirect->setHits($hits);
$redirect->setUniqueHits($uniqueHits);
$this->em->persist($redirect);
$trackable = new Trackable();
$trackable->setChannelId($channelId);
$trackable->setChannel('focus');
$trackable->setHits($hits);
$trackable->setUniqueHits($uniqueHits);
$trackable->setRedirect($redirect);
$this->em->persist($trackable);
}
/**
* @return array<int,array<int,mixed>>
*/
private function domTableToArray(Crawler $crawler): array
{
return $crawler->filter('tr')->each(fn ($tr) => $tr->filter('td')->each(fn ($td) => trim($td->text())));
}
}

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Form\Type;
use MauticPlugin\MauticFocusBundle\Form\Type\ContentType;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Form\FormBuilderInterface;
class ContentTypeTest extends TestCase
{
/**
* @var mixed|\PHPUnit\Framework\MockObject\MockObject|FormBuilderInterface
*/
private \PHPUnit\Framework\MockObject\MockObject $formBuilder;
protected function setUp(): void
{
$this->formBuilder = $this->createMock(FormBuilderInterface::class);
}
public function testBuilderForm(): void
{
$this->formBuilder->expects(self::exactly(7))->method('add')->willReturnSelf();
$options = [];
$contentType = new ContentType();
$contentType->buildForm($this->formBuilder, $options);
}
}

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Functional\Controller;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use Mautic\ProjectBundle\Entity\Project;
use MauticPlugin\MauticFocusBundle\Entity\Focus;
use PHPUnit\Framework\Assert;
class FocusControllerTest extends MauticMysqlTestCase
{
public function testFocusWithProject(): void
{
$focus = new Focus();
$focus->setName('Test Focus');
$focus->setType('notice');
$focus->setStyle('bar');
$this->em->persist($focus);
$project = new Project();
$project->setName('Test Project');
$this->em->persist($project);
$this->em->flush();
$this->em->clear();
$crawler = $this->client->request('GET', '/s/focus/edit/'.$focus->getId());
$form = $crawler->selectButton('Save')->form();
$form['focus[projects]']->setValue((string) $project->getId());
$this->client->submit($form);
$this->assertResponseIsSuccessful();
$savedFocus = $this->em->find(Focus::class, $focus->getId());
Assert::assertSame($project->getId(), $savedFocus->getProjects()->first()->getId());
}
}

View File

@@ -0,0 +1,99 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Functional\Controller;
use Mautic\ProjectBundle\Tests\Functional\AbstractProjectSearchTestCase;
use MauticPlugin\MauticFocusBundle\Entity\Focus;
final class FocusProjectSearchFunctionalTest extends AbstractProjectSearchTestCase
{
#[\PHPUnit\Framework\Attributes\DataProvider('searchDataProvider')]
public function testProjectSearch(string $searchTerm, array $expectedEntities, array $unexpectedEntities): void
{
$projectOne = $this->createProject('Project One');
$projectTwo = $this->createProject('Project Two');
$projectThree = $this->createProject('Project Three');
$focusAlpha = $this->createFocus('Focus Alpha');
$focusBeta = $this->createFocus('Focus Beta');
$this->createFocus('Focus Gamma');
$this->createFocus('Focus Delta');
$focusAlpha->addProject($projectOne);
$focusAlpha->addProject($projectTwo);
$focusBeta->addProject($projectTwo);
$focusBeta->addProject($projectThree);
$this->em->flush();
$this->em->clear();
$this->searchAndAssert($searchTerm, $expectedEntities, $unexpectedEntities, ['/api/focus', '/s/focus']);
}
/**
* @return \Generator<string, array{searchTerm: string, expectedEntities: array<string>, unexpectedEntities: array<string>}>
*/
public static function searchDataProvider(): \Generator
{
yield 'search by one project' => [
'searchTerm' => 'project:"Project Two"',
'expectedEntities' => ['Focus Alpha', 'Focus Beta'],
'unexpectedEntities' => ['Focus Gamma', 'Focus Delta'],
];
yield 'search by one project AND focus name' => [
'searchTerm' => 'project:"Project Two" AND Beta',
'expectedEntities' => ['Focus Beta'],
'unexpectedEntities' => ['Focus Alpha', 'Focus Gamma', 'Focus Delta'],
];
yield 'search by one project OR focus name' => [
'searchTerm' => 'project:"Project Two" OR Gamma',
'expectedEntities' => ['Focus Alpha', 'Focus Beta', 'Focus Gamma'],
'unexpectedEntities' => ['Focus Delta'],
];
yield 'search by NOT one project' => [
'searchTerm' => '!project:"Project Two"',
'expectedEntities' => ['Focus Gamma', 'Focus Delta'],
'unexpectedEntities' => ['Focus Alpha', 'Focus Beta'],
];
yield 'search by two projects with AND' => [
'searchTerm' => 'project:"Project Two" AND project:"Project Three"',
'expectedEntities' => ['Focus Beta'],
'unexpectedEntities' => ['Focus Alpha', 'Focus Gamma', 'Focus Delta'],
];
yield 'search by two projects with NOT AND' => [
'searchTerm' => '!project:"Project Two" AND !project:"Project Three"',
'expectedEntities' => ['Focus Gamma', 'Focus Delta'],
'unexpectedEntities' => ['Focus Alpha', 'Focus Beta'],
];
yield 'search by two projects with OR' => [
'searchTerm' => 'project:"Project Two" OR project:"Project Three"',
'expectedEntities' => ['Focus Alpha', 'Focus Beta'],
'unexpectedEntities' => ['Focus Gamma', 'Focus Delta'],
];
yield 'search by two projects with NOT OR' => [
'searchTerm' => '!project:"Project Two" OR !project:"Project Three"',
'expectedEntities' => ['Focus Alpha', 'Focus Gamma', 'Focus Delta'],
'unexpectedEntities' => ['Focus Beta'],
];
}
private function createFocus(string $name): Focus
{
$focus = new Focus();
$focus->setName($name);
$focus->setType('notice');
$focus->setStyle('bar');
$this->em->persist($focus);
return $focus;
}
}

View File

@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Functional\Controller;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use Mautic\PageBundle\Entity\Redirect;
use MauticPlugin\MauticFocusBundle\Entity\Focus;
use PHPUnit\Framework\Assert;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class PublicControllerTest extends MauticMysqlTestCase
{
#[\PHPUnit\Framework\Attributes\PreserveGlobalState(false)]
#[\PHPUnit\Framework\Attributes\RunInSeparateProcess]
public function testGenerateActionWithContactTokenInLinkUrl(): void
{
$linkUrl = 'https://{contactfield=site_url}/tour';
$focus = new Focus();
$focus->setName('Test');
$focus->setType('link');
$focus->setStyle('modal');
$focus->setProperties([
'content' => [
'headline' => '',
'link_text' => 'Link text',
'link_url' => $linkUrl,
'font' => 'Arial, Helvetica, sans-serif',
'link_new_window' => 1,
],
'when' => 'immediately',
'modal' => [
'placement' => 'top',
],
'frequency' => 'everypage',
'colors' => [
'primary' => '#4e5d9d',
'text' => '#000000',
'button' => '#fdb933',
'button_text' => '#ffffff',
],
]);
$this->em->persist($focus);
$this->em->flush();
$this->em->clear();
$this->client->request(Request::METHOD_GET, sprintf('/focus/%s.js', $focus->getId()));
$content = $this->client->getResponse()->getContent();
$redirects = $this->em->getRepository(Redirect::class)->findAll();
Assert::assertCount(1, $redirects);
/** @var Redirect $redirect */
$redirect = reset($redirects);
Assert::assertSame($linkUrl, $redirect->getUrl());
$url = $this->router->generate('mautic_url_redirect', ['redirectId' => $redirect->getRedirectId()], UrlGeneratorInterface::ABSOLUTE_URL);
$twig = $this->getContainer()->get('twig');
if (!$twig->hasExtension(\Twig\Extension\EscaperExtension::class)) {
$twig->addExtension(new \Twig\Extension\EscaperExtension());
}
$url = $twig->getRuntime(\Twig\Runtime\EscaperRuntime::class)->escape($url, 'js');
Assert::assertStringContainsString($url, $content);
}
}

View File

@@ -0,0 +1,121 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Model;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\PageBundle\Entity\Hit;
use MauticPlugin\MauticFocusBundle\Entity\Focus;
use MauticPlugin\MauticFocusBundle\Entity\Stat;
use MauticPlugin\MauticFocusBundle\Model\FocusModel;
class FocusModelFunctionalTest extends MauticMysqlTestCase
{
private Lead $lead;
private FocusModel $focusModel;
protected function setUp(): void
{
parent::setUp();
$this->focusModel = static::getContainer()->get('mautic.focus.model.focus');
$this->lead = $this->createLead();
}
public function testGetStats(): void
{
$focusPopupA = $this->createFocus('popup focus A');
$focusStatExpected = $this->setTestsData($this->lead, $focusPopupA);
$to = new \DateTime('+1 day');
$from = new \DateTime('-1 month');
$focusStat = $this->focusModel->getStats($focusPopupA, null, $from, $to);
$focusViewsCount = array_sum($focusStat['datasets'][0]['data']);
$focusClickCount = array_sum($focusStat['datasets'][1]['data']);
$this->assertEquals($focusStatExpected['view'], $focusViewsCount);
$this->assertEquals($focusStatExpected['click'], $focusClickCount);
}
/**
* @return array<string, int>
*/
private function setTestsData(Lead $lead, Focus $focus): array
{
$hitPopupA = new Hit();
$hitPopupA->setLead($lead);
$this->focusModel->addStat($focus, Stat::TYPE_NOTIFICATION, null, $lead);
$this->focusModel->addStat($focus, Stat::TYPE_CLICK, $hitPopupA, $lead);
$this->focusModel->addStat($focus, Stat::TYPE_CLICK, $hitPopupA, $lead);
$this->focusModel->addStat($focus, Stat::TYPE_CLICK, $hitPopupA, $lead);
$this->focusModel->addStat($focus, Stat::TYPE_CLICK, $hitPopupA, $lead);
return ['view' => 1, 'click' => 4];
}
private function createFocus(string $name): Focus
{
$focus = new Focus();
$focus->setName($name);
$focus->setType('link');
$focus->setStyle('modal');
$focus->setProperties([
'bar' => [
'allow_hide' => 1,
'push_page' => 1,
'sticky' => 1,
'size' => 'large',
'placement' => 'top',
],
'modal' => [
'placement' => 'top',
],
'notification' => [
'placement' => 'top_left',
],
'page' => [],
'animate' => 0,
'link_activation' => 1,
'colors' => [
'primary' => '4e5d9d',
'text' => '000000',
'button' => 'fdb933',
'button_text' => 'ffffff',
],
'content' => [
'headline' => null,
'tagline' => null,
'link_text' => null,
'link_url' => null,
'link_new_window' => 1,
'font' => 'Arial, Helvetica, sans-serif',
'css' => null,
],
'when' => 'immediately',
'timeout' => null,
'frequency' => 'everypage',
'stop_after_conversion' => 1,
]);
$this->focusModel->saveEntity($focus);
return $focus;
}
private function createLead(): Lead
{
$lead = new Lead();
$lead->setFirstname('Contact');
$lead->setEmail('test@test.com');
$this->em->persist($lead);
$this->em->flush();
return $lead;
}
}

View File

@@ -0,0 +1,103 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Model;
use Doctrine\ORM\EntityManagerInterface;
use Mautic\CoreBundle\Helper\CoreParametersHelper;
use Mautic\CoreBundle\Helper\UserHelper;
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
use Mautic\CoreBundle\Translation\Translator;
use Mautic\FormBundle\Model\FormModel;
use Mautic\LeadBundle\Model\FieldModel;
use Mautic\LeadBundle\Tracker\ContactTracker;
use Mautic\PageBundle\Model\TrackableModel;
use MauticPlugin\MauticFocusBundle\Model\FocusModel;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Rule\InvokedCount;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Twig\Environment;
class FocusModelTest extends TestCase
{
/**
* @var ContactTracker|MockObject
*/
private MockObject $contactTracker;
/**
* @var MockObject|EventDispatcherInterface
*/
private MockObject $dispatcher;
/**
* @var FormModel|MockObject
*/
private MockObject $formModel;
/**
* @var FieldModel|MockObject
*/
private MockObject $leadFieldModel;
/**
* @var Environment|mixed|MockObject
*/
private MockObject $twig;
/**
* @var TrackableModel|mixed|MockObject
*/
private MockObject $trackableModel;
protected function setUp(): void
{
$this->formModel = $this->createMock(FormModel::class);
$this->trackableModel = $this->createMock(TrackableModel::class);
$this->twig = $this->createMock(Environment::class);
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
$this->leadFieldModel = $this->createMock(FieldModel::class);
$this->contactTracker = $this->createMock(ContactTracker::class);
parent::setUp();
}
#[\PHPUnit\Framework\Attributes\DataProvider('focusTypeProvider')]
public function testGetContentWithForm(string $type, InvokedCount $count): void
{
$this->formModel->expects(self::once())->method('getPages')->willReturn(['', '']);
$this->formModel->expects($count)->method('getEntity');
$focusModel = new FocusModel(
$this->formModel,
$this->trackableModel,
$this->twig,
$this->leadFieldModel,
$this->contactTracker,
$this->createMock(EntityManagerInterface::class),
$this->createMock(CorePermissions::class),
$this->dispatcher,
$this->createMock(UrlGeneratorInterface::class),
$this->createMock(Translator::class),
$this->createMock(UserHelper::class),
$this->createMock(LoggerInterface::class),
$this->createMock(CoreParametersHelper::class)
);
$focus = [
'form' => 'xxx',
'type' => $type,
];
$focusModel->getContent($focus);
}
public static function focusTypeProvider(): \Generator
{
yield ['form', self::once()];
yield ['notice', self::never()];
}
}

View File

@@ -0,0 +1,13 @@
--TEST--
compile LESS
--TEMPLATE--
{{ less|less_compile }}
--DATA--
return ['less' => "@primarycolor: #FF7F50;@color:#800080;h2{color: @primarycolor;}h3{color: @color;}"]
--EXPECT--
h2 {
color: #FF7F50;
}
h3 {
color: #800080;
}

View File

@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Twig;
use MauticPlugin\MauticFocusBundle\Twig\Extension\FocusBundleExtension;
use Twig\Extension\ExtensionInterface;
/**
* @see https://twig.symfony.com/doc/2.x/advanced.html#functional-tests
*/
class TwigIntegrationTest extends \Twig\Test\IntegrationTestCase
{
/**
* @return ExtensionInterface[]
*/
public function getExtensions(): array
{
return [
new FocusBundleExtension(),
];
}
public static function getFixturesDirectory(): string
{
return __DIR__.'/Fixtures/';
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace MauticPlugin\MauticFocusBundle\Tests\Unit\Helper;
use MauticPlugin\MauticFocusBundle\Helper\IframeAvailabilityChecker;
use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Contracts\Translation\TranslatorInterface;
class IframeAvailabilityCheckerTest extends \PHPUnit\Framework\TestCase
{
/**
* @var MockObject&TranslatorInterface
*/
private MockObject $translator;
private IframeAvailabilityChecker $helper;
public function setUp(): void
{
$this->translator = $this->createMock(TranslatorInterface::class);
$this->helper = new IframeAvailabilityChecker($this->translator);
}
public function testCheckProtocolMismatch(): void
{
$currentScheme = 'https';
$url = 'http://google.com'; // NOSONAR
$translatedErrorMessage = 'error';
$expectedResponseContent = [
'status' => 0,
'errorMessage' => $translatedErrorMessage,
];
$this->translator->expects($this->once())
->method('trans')
->with(
'mautic.focus.protocol.mismatch',
[
'%url%' => str_replace('http://', 'https://', $url),
]
)
->willReturn($translatedErrorMessage);
/** @var JsonResponse $response */
$response = $this->helper->check($url, $currentScheme);
$responseBody = json_decode($response->getContent(), true);
$this->assertEquals($expectedResponseContent, $responseBody);
}
}

View File

@@ -0,0 +1,107 @@
<?php
declare(strict_types=1);
namespace MauticPlugin\MauticFocusBundle\Tests\Helper;
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
use MauticPlugin\MauticFocusBundle\Entity\Focus;
use MauticPlugin\MauticFocusBundle\Helper\TokenHelper;
use MauticPlugin\MauticFocusBundle\Model\FocusModel;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Routing\RouterInterface;
class TokenHelperTest extends TestCase
{
/**
* @var FocusModel|MockObject
*/
private MockObject $model;
/**
* @var MockObject|RouterInterface
*/
private MockObject $router;
/**
* @var CorePermissions|MockObject
*/
private MockObject $security;
private TokenHelper $helper;
protected function setUp(): void
{
parent::setUp();
$this->model = $this->createMock(FocusModel::class);
$this->router = $this->createMock(RouterInterface::class);
$this->security = $this->createMock(CorePermissions::class);
$this->helper = new TokenHelper($this->model, $this->router, $this->security);
}
public function testFindFocusTokensNotFound(): void
{
$content = 'content';
self::assertSame([], $this->helper->findFocusTokens($content));
}
public function testFindFocusTokensFound(): void
{
$content = 'content {focus=1}';
self::assertSame(['{focus=1}' => ''], $this->helper->findFocusTokens($content));
}
public function testFindFocusTokensFoundAddScriptByFocusPublishedStatus(): void
{
$focusItemId = 1;
$content = "content {focus=$focusItemId}";
$focusItem = new Focus();
$focusItem->setIsPublished(true);
$this->model->expects(self::once())
->method('getEntity')
->with($focusItemId)
->willReturn($focusItem);
self::assertSame(
['{focus=1}' => '<script src="" type="text/javascript" charset="utf-8" async="async"></script>'],
$this->helper->findFocusTokens($content)
);
}
public function testFindFocusTokensFoundAddScriptByAccessCheck(): void
{
$focusItemId = 1;
$createdById = 2;
$content = "content {focus=$focusItemId}";
$focusItem = new Focus();
$focusItem->setIsPublished(false);
$focusItem->setCreatedBy($createdById);
$this->model->expects(self::once())
->method('getEntity')
->with($focusItemId)
->willReturn($focusItem);
$this->security->expects(self::once())
->method('hasEntityAccess')
->with(
'focus:items:viewown',
'focus:items:viewother',
$focusItem->getCreatedBy()
)
->willReturn(true);
self::assertSame(
['{focus=1}' => '<script src="" type="text/javascript" charset="utf-8" async="async"></script>'],
$this->helper->findFocusTokens($content)
);
}
}