Skip to content

Commit 20606d3

Browse files
committed
Fix: test
1 parent be0527d commit 20606d3

5 files changed

Lines changed: 290 additions & 24 deletions

File tree

src/Controller/BaseController.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use PhpList\RestApiClient\Endpoint\AuthClient;
88
use PhpList\RestApiClient\Entity\Administrator;
9-
use PhpList\RestApiClient\Exception\AuthenticationException;
9+
use PhpList\RestApiClient\Exception\ApiException;
1010
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
1111

1212
class BaseController extends AbstractController
@@ -20,7 +20,7 @@ protected function getAdmin(): ?Administrator
2020
{
2121
try {
2222
$admin = $this->authClient->getSessionUser();
23-
} catch (AuthenticationException $e) {
23+
} catch (ApiException) {
2424
$admin = null;
2525
}
2626

src/Controller/PublicSubscribeController.php

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function __construct(
4141
public function unsubscribe(Request $request, int $pageId): Response
4242
{
4343
$page = $this->subscribePagesClient->getPublicSubscribePage($pageId);
44-
$pageData = $page->data;
44+
$pageData = $this->normalizePublicPageData($page->data);
4545
$languageFile = $pageData['language_file'] ?? 'english.inc';
4646
$languageTexts = $this->languageService->loadLanguageTexts(is_string($languageFile) ? $languageFile : null);
4747

@@ -93,16 +93,16 @@ public function subscribe(Request $request, int $pageId): Response
9393
{
9494
$admin = $this->getAdmin();
9595
$page = $this->subscribePagesClient->getPublicSubscribePage($pageId);
96-
$pageData = $page->data;
96+
$pageData = $this->normalizePublicPageData($page->data);
9797
$isSubmitted = $request->isMethod('POST');
9898

9999
$languageFile = $pageData['language_file'] ?? 'english.inc';
100100
$languageTexts = $this->languageService->loadLanguageTexts(is_string($languageFile) ? $languageFile : null);
101101

102102
$htmlChoice = $this->formBuilder->normalizeHtmlChoice($pageData['htmlchoice'] ?? null);
103-
$emailDoubleEntry = strtolower($pageData['emaildoubleentry'] ?? '') === 'yes';
103+
$emailDoubleEntry = strtolower((string) ($pageData['emaildoubleentry'] ?? '')) === 'yes';
104104

105-
$lists = $page->data['lists'];
105+
$lists = $pageData['lists'];
106106
$availableListIds = array_map(static fn ($list): int => (int) $list['id'], $lists);
107107

108108
$attributes = $this->formBuilder->buildAttributeConfig($pageData);
@@ -165,4 +165,67 @@ public function subscribe(Request $request, int $pageId): Response
165165
'signature' => $this->config->getValue(ConfigOption::PoweredByImage)
166166
]);
167167
}
168+
169+
/**
170+
* @param array<string,mixed> $pageData
171+
* @return array<string,mixed>
172+
*/
173+
private function normalizePublicPageData(array $pageData): array
174+
{
175+
$pageData['header'] = $this->scalarString($pageData['header'] ?? null);
176+
$pageData['footer'] = $this->scalarString($pageData['footer'] ?? null);
177+
$pageData['attributes'] = is_array($pageData['attributes'] ?? null) ? $pageData['attributes'] : [];
178+
$pageData['lists'] = $this->normalizePublicLists($pageData['lists'] ?? []);
179+
180+
return $pageData;
181+
}
182+
183+
/**
184+
* @return list<array{id:int,name:string,description:string,list_position:int}>
185+
*/
186+
private function normalizePublicLists(mixed $lists): array
187+
{
188+
if (!is_array($lists)) {
189+
return [];
190+
}
191+
192+
$normalizedLists = [];
193+
foreach ($lists as $list) {
194+
$normalizedList = $this->normalizePublicList($list);
195+
if ($normalizedList === null) {
196+
continue;
197+
}
198+
199+
$normalizedLists[] = $normalizedList;
200+
}
201+
202+
return $normalizedLists;
203+
}
204+
205+
/**
206+
* @return array{id:int,name:string,description:string,list_position:int}|null
207+
*/
208+
private function normalizePublicList(mixed $list): ?array
209+
{
210+
if (!is_array($list)) {
211+
return null;
212+
}
213+
214+
$id = (int) ($list['id'] ?? 0);
215+
if ($id <= 0) {
216+
return null;
217+
}
218+
219+
return [
220+
'id' => $id,
221+
'name' => $this->scalarString($list['name'] ?? null, 'List ' . $id),
222+
'description' => $this->scalarString($list['description'] ?? null),
223+
'list_position' => (int) ($list['list_position'] ?? 0),
224+
];
225+
}
226+
227+
private function scalarString(mixed $value, string $default = ''): string
228+
{
229+
return is_scalar($value) ? (string) $value : $default;
230+
}
168231
}

templates/public/base.html.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
<script src="{{ asset('build/app.js', 'phplist_web_frontend') }}" defer></script>
1515
{% endblock %}
1616

17-
{{ data['header']|unescape_header|raw }}
17+
{{ data['header']|default('')|unescape_header|raw }}
1818

1919
{% block body %}{% endblock %}
2020

2121
{{ signature|raw }}
2222

23-
{{ data['footer']|unescape_header|raw }}
23+
{{ data['footer']|default('')|unescape_header|raw }}

tests/Integration/Controller/PublicSubscribeControllerPantherTest.php

Lines changed: 122 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
use PHPUnitRetry\RetryAnnotationTrait;
88
use PHPUnitRetry\RetryTrait;
9+
use Symfony\Component\Panther\Client;
910
use Symfony\Component\Panther\PantherTestCase;
11+
use Throwable;
1012

1113
/**
1214
* @retryAttempts 1
@@ -18,15 +20,22 @@ class PublicSubscribeControllerPantherTest extends PantherTestCase
1820
use RetryAnnotationTrait;
1921
use RetryTrait;
2022

23+
private const PANTHER_OPTIONS = [
24+
'browser' => self::CHROME,
25+
'connection_timeout_in_ms' => 10000,
26+
'env' => [
27+
'APP_ENV' => 'test',
28+
'APP_DEBUG' => '1',
29+
],
30+
];
31+
2132
/**
2233
* @dataProvider publicSubscribeAssetRoutesProvider
2334
*/
2435
public function testAnonymousUserCanAccessPublicSubscribeAssetRoutes(string $path): void
2536
{
26-
$client = static::createPantherClient([
27-
'browser' => static::CHROME,
28-
'connection_timeout_in_ms' => 10000,
29-
]);
37+
$client = static::createPantherClient(self::PANTHER_OPTIONS);
38+
$client->getCookieJar()->clear();
3039
$client->request('GET', $path);
3140

3241
$currentPath = (string) parse_url($client->getCurrentURL(), PHP_URL_PATH);
@@ -52,10 +61,8 @@ public function publicSubscribeAssetRoutesProvider(): array
5261
*/
5362
public function testAnonymousUserCanAccessPublicSubscribeAndUnsubscribePages(string $path): void
5463
{
55-
$client = static::createPantherClient([
56-
'browser' => static::CHROME,
57-
'connection_timeout_in_ms' => 10000,
58-
]);
64+
$client = static::createPantherClient(self::PANTHER_OPTIONS);
65+
$client->getCookieJar()->clear();
5966
$client->request('GET', $path);
6067

6168
$currentPath = (string) parse_url($client->getCurrentURL(), PHP_URL_PATH);
@@ -66,14 +73,19 @@ public function testAnonymousUserCanAccessPublicSubscribeAndUnsubscribePages(str
6673

6774
public function testSubscribePageDisplaysEmailFieldAndSubmitButton(): void
6875
{
69-
$client = static::createPantherClient([
70-
'browser' => static::CHROME,
71-
'connection_timeout_in_ms' => 10000,
72-
]);
73-
$client->request('GET', '/index.php/subscribe/1');
74-
75-
$client->takeScreenshot('var/screenshots/public-subscribe-0.png');
76-
$client->waitFor('form.legacy-form', 10);
76+
$client = static::createPantherClient(self::PANTHER_OPTIONS);
77+
try {
78+
$client->getCookieJar()->clear();
79+
$client->request('GET', '/index.php/subscribe/1');
80+
81+
$client->takeScreenshot('var/screenshots/public-subscribe-0.png');
82+
$client->waitFor('form.legacy-form', 10);
83+
} catch (Throwable $throwable) {
84+
$client->takeScreenshot('var/screenshots/public-subscribe-error.png');
85+
$this->writePublicSubscribeDiagnostics($client, $throwable);
86+
87+
throw $throwable;
88+
}
7789
$client->takeScreenshot('var/screenshots/public-subscribe-1.png');
7890

7991
$currentPath = (string) parse_url($client->getCurrentURL(), PHP_URL_PATH);
@@ -95,4 +107,98 @@ public function publicSubscribePageRoutesProvider(): array
95107
'unsubscribe page route' => ['/index.php/unsubscribe/1'],
96108
];
97109
}
110+
111+
private function writePublicSubscribeDiagnostics(Client $client, Throwable $throwable): void
112+
{
113+
$diagnosticsDir = __DIR__ . '/../../../var/screenshots';
114+
if (!is_dir($diagnosticsDir)) {
115+
mkdir($diagnosticsDir, 0777, true);
116+
}
117+
118+
$pageSource = $this->readPageSource($client);
119+
file_put_contents($diagnosticsDir . '/public-subscribe-error.html', $pageSource);
120+
file_put_contents(
121+
$diagnosticsDir . '/public-subscribe-error.txt',
122+
implode("\n\n", [
123+
'Exception: ' . $throwable::class,
124+
'Message: ' . $throwable->getMessage(),
125+
'Current URL: ' . $this->readCurrentUrl($client),
126+
'Page title: ' . $this->readPageTitle($client),
127+
'Body text: ' . $this->readBodyText($client),
128+
'Recent Symfony logs:' . "\n" . $this->readRecentSymfonyLogs(),
129+
])
130+
);
131+
132+
fwrite(STDERR, "Public subscribe diagnostics written to var/screenshots/public-subscribe-error.*\n");
133+
}
134+
135+
private function readPageSource(Client $client): string
136+
{
137+
try {
138+
return $client->getPageSource();
139+
} catch (Throwable $throwable) {
140+
return 'Unable to read page source: ' . $throwable->getMessage();
141+
}
142+
}
143+
144+
private function readCurrentUrl(Client $client): string
145+
{
146+
try {
147+
return $client->getCurrentURL();
148+
} catch (Throwable $throwable) {
149+
return 'Unable to read current URL: ' . $throwable->getMessage();
150+
}
151+
}
152+
153+
private function readPageTitle(Client $client): string
154+
{
155+
try {
156+
return $client->getTitle();
157+
} catch (Throwable $throwable) {
158+
return 'Unable to read page title: ' . $throwable->getMessage();
159+
}
160+
}
161+
162+
private function readBodyText(Client $client): string
163+
{
164+
try {
165+
return $client->getCrawler()->filter('body')->text('', true);
166+
} catch (Throwable $throwable) {
167+
return 'Unable to read body text: ' . $throwable->getMessage();
168+
}
169+
}
170+
171+
private function readRecentSymfonyLogs(): string
172+
{
173+
$projectDir = dirname(__DIR__, 3);
174+
$paths = array_merge(
175+
glob($projectDir . '/var/logs/*.log') ?: [],
176+
glob($projectDir . '/var/log/*.log') ?: []
177+
);
178+
179+
if ($paths === []) {
180+
return sprintf('No log files found under %s/var/logs or %s/var/log.', $projectDir, $projectDir);
181+
}
182+
183+
$logs = [];
184+
foreach (array_unique($paths) as $path) {
185+
$logs[] = sprintf("==> %s <==\n%s", $path, $this->readRecentLogLines($path));
186+
}
187+
188+
return implode("\n\n", $logs);
189+
}
190+
191+
private function readRecentLogLines(string $path): string
192+
{
193+
if (!is_file($path)) {
194+
return sprintf('Log file %s does not exist.', $path);
195+
}
196+
197+
$lines = file($path, FILE_IGNORE_NEW_LINES);
198+
if ($lines === false) {
199+
return sprintf('Unable to read log file %s.', $path);
200+
}
201+
202+
return implode("\n", array_slice($lines, -80));
203+
}
98204
}

0 commit comments

Comments
 (0)