Fix PHP code style issues / php-code-styling (push) Waiting to run
PHPStan / phpstan (push) Waiting to run
run-tests / P8.3 - L11.* - prefer-lowest - ubuntu-latest (push) Waiting to run
run-tests / P8.3 - L11.* - prefer-stable - ubuntu-latest (push) Waiting to run
run-tests / P8.4 - L11.* - prefer-lowest - ubuntu-latest (push) Waiting to run
run-tests / P8.4 - L11.* - prefer-stable - ubuntu-latest (push) Waiting to run
run-tests / P8.3 - L12.* - prefer-lowest - ubuntu-latest (push) Waiting to run
run-tests / P8.3 - L12.* - prefer-stable - ubuntu-latest (push) Waiting to run
run-tests / P8.4 - L12.* - prefer-lowest - ubuntu-latest (push) Waiting to run
run-tests / P8.4 - L12.* - prefer-stable - ubuntu-latest (push) Waiting to run
dependabot-auto-merge / dependabot (pull_request_target) Skipped
- Replace symfony 7.4.x-dev constraints with stable ranges so the
package installs with minimum-stability stable
- Add the Cision facade referenced in composer.json and a config file
(slug, timezone); the constructor now falls back to config('cision.slug')
- Convert feed timestamps with a real timezone instead of a hardcoded +2h,
which was off by an hour during winter time
- Return false from fetchContent() when the request fails or the page
has no article/heading, instead of throwing
- Fix italic paragraph detection, which never matched
- Fix literal '\n' in HtmlCleaner whitespace cleanup
- Normalize empty feed elements to empty strings
- Update README and add tests for the above
108 lines
3.9 KiB
PHP
108 lines
3.9 KiB
PHP
<?php
|
|
|
|
use Illuminate\Support\Facades\Http;
|
|
use Mattitja\Cision\Cision;
|
|
|
|
it('can fetch press releases from the RSS feed', function () {
|
|
Http::fake([
|
|
'news.cision.com/*' => Http::response(file_get_contents(__DIR__.'/Fixtures/rss-press.xml')),
|
|
]);
|
|
|
|
$cision = new Cision('test-company');
|
|
$data = $cision->press();
|
|
|
|
expect($data)->toBeArray();
|
|
expect($data)->toHaveKey('items');
|
|
expect($data['items'])->not->toBeEmpty();
|
|
|
|
$item = $data['items'][0];
|
|
expect($item)->toHaveKeys(['guid', 'title', 'description', 'link', 'created_at']);
|
|
});
|
|
|
|
it('can fetch and parse full article content', function () {
|
|
Http::fake([
|
|
'news.cision.com/*' => Http::response(file_get_contents(__DIR__.'/Fixtures/article.html')),
|
|
]);
|
|
|
|
$cision = new Cision('test-company');
|
|
$content = $cision->fetchContent('https://news.cision.com/se/example/r/test,c123456');
|
|
|
|
expect($content)->toHaveKeys(['header', 'published_at', 'content']);
|
|
expect($content['header'])->not->toBeEmpty();
|
|
expect($content['content'])->toContain('<p');
|
|
});
|
|
|
|
it('converts feed timestamps to Stockholm time in summer and winter', function () {
|
|
$rss = fn (string $date) => <<<XML
|
|
<?xml version="1.0" encoding="UTF-8" ?>
|
|
<rss version="2.0"><channel>
|
|
<item><guid>a</guid><title>A</title><description>D</description><link>L</link><pubDate>{$date}</pubDate></item>
|
|
</channel></rss>
|
|
XML;
|
|
|
|
Http::fakeSequence()
|
|
->push($rss('Fri, 04 Jul 2025 07:55:00 GMT'))
|
|
->push($rss('Wed, 15 Jan 2025 07:55:00 GMT'));
|
|
|
|
$cision = new Cision('test-company');
|
|
|
|
expect($cision->press()['items'][0]['created_at'])->toBe('2025-07-04 09:55:00');
|
|
expect($cision->press()['items'][0]['created_at'])->toBe('2025-01-15 08:55:00');
|
|
});
|
|
|
|
it('returns empty strings for empty feed elements', function () {
|
|
Http::fake([
|
|
'news.cision.com/*' => Http::response(<<<'XML'
|
|
<?xml version="1.0" encoding="UTF-8" ?>
|
|
<rss version="2.0"><channel>
|
|
<item><guid>a</guid><title>A</title><description></description><link>L</link><pubDate>Fri, 04 Jul 2025 07:55:00 GMT</pubDate></item>
|
|
</channel></rss>
|
|
XML),
|
|
]);
|
|
|
|
expect((new Cision('test-company'))->press()['items'][0]['description'])->toBe('');
|
|
});
|
|
|
|
it('returns false when the feed request fails', function () {
|
|
Http::fake(['news.cision.com/*' => Http::response('', 500)]);
|
|
|
|
expect((new Cision('test-company'))->press())->toBeFalse();
|
|
});
|
|
|
|
it('returns false when the article request fails', function () {
|
|
Http::fake(['news.cision.com/*' => Http::response('', 404)]);
|
|
|
|
expect((new Cision('test-company'))->fetchContent('https://news.cision.com/se/x'))->toBeFalse();
|
|
});
|
|
|
|
it('returns false when the page has no article', function () {
|
|
Http::fake(['news.cision.com/*' => Http::response('<html><body><p>Nope</p></body></html>')]);
|
|
|
|
expect((new Cision('test-company'))->fetchContent('https://news.cision.com/se/x'))->toBeFalse();
|
|
});
|
|
|
|
it('marks paragraphs that start with italic text', function () {
|
|
Http::fake([
|
|
'news.cision.com/*' => Http::response(file_get_contents(__DIR__.'/Fixtures/article.html')),
|
|
]);
|
|
|
|
$content = (new Cision('test-company'))->fetchContent('https://news.cision.com/se/x')['content'];
|
|
|
|
expect($content)
|
|
->toContain('<p class="italic"><em>Italic sentence.</em></p>')
|
|
->toContain('<p><strong>Lead:</strong> This is a test article paragraph.</p>')
|
|
->not->toContain('Test Article Header');
|
|
});
|
|
|
|
it('uses the configured slug when none is given', function () {
|
|
config()->set('cision.slug', 'configured-company');
|
|
|
|
Http::fake([
|
|
'news.cision.com/*' => Http::response(file_get_contents(__DIR__.'/Fixtures/rss-press.xml')),
|
|
]);
|
|
|
|
Mattitja\Cision\Facades\Cision::press();
|
|
|
|
Http::assertSent(fn ($request) => str_contains($request->url(), 'n=configured-company'));
|
|
});
|