Files
xxx/tests/php/Unit/DisplayStoriesTest.php
tim 8d6282348c Show no date for a story without one.
Such a story showed the date of the story before it, or caused a warning when it came first.
2026-09-26 15:27:51 +02:00

167 lines
7.3 KiB
PHP

<?php
namespace Xxx\Tests\Unit;
use Xxx\Tests\Support\SiteData;
use Xxx\Tests\Support\TestCase;
// display_stories() in get_data.lib.php
class DisplayStoriesTest extends TestCase {
protected function setUp(): void {
parent::setUp();
$GLOBALS['num_stories'] = 5;
SiteData::install(array(
'xxx' => array(
array('id' => 1, 'title' => 'First <em>title</em>', 'author' => 'Ann & "Bo"', 'date' => '2020-01-02 03:04:05',
'story' => '<p onclick="steal()">One <script>alert(1)</script>hundred</p>'),
array('id' => 2, 'title' => 'Second', 'author' => 'Cy', 'date' => '2020-01-01 10:00:00', 'story' => '<p>Two</p>'),
array('id' => 3, 'title' => 'Picture', 'author' => 'Di', 'date' => '2019-12-31 10:00:00', 'story' => '',
'img' => 'PNG', 'mime' => 'image/png', 'hidden' => '1'),
),
'queue' => array(
array('id' => 20, 'title' => 'Waiting', 'author' => 'Ed', 'date' => '2020-02-01 10:00:00'),
),
));
open_db('open');
}
public function testListsStoriesWithEscapedFields(): void {
$page = display_stories();
$this->assertStringStartsWith('<ul class="article-list">', $page);
$this->assertSame(2, substr_count($page, '<li class="box">'));
$this->assertStringContainsString('<a href="/article?id=1">First &lt;em&gt;title&lt;/em&gt;</a>', $page);
$this->assertStringContainsString('<dd class="author">Ann &amp; &quot;Bo&quot;</dd>', $page);
$this->assertStringNotContainsString('<em>title</em>', $page);
}
public function testStoryHtmlIsPurified(): void {
$page = display_stories();
$this->assertStringContainsString('<p>One hundred</p>', $page);
$this->assertStringNotContainsString('onclick', $page);
$this->assertStringNotContainsString('alert', $page);
}
public function testDatesAreShownWithoutSecondsAndMarkedUp(): void {
$page = display_stories();
$datetime = date('Y-m-d\TH:i:sP', strtotime('2020-01-02 03:04:05'));
$this->assertStringContainsString('<time datetime="' . $datetime . '">2020-01-02 03:04</time>', $page);
}
// A story without a date shows no date, not the date of the story before it
public function testAStoryWithoutADateShowsNone(): void {
SiteData::install(array('xxx' => array(
array('id' => 1, 'title' => 'Dated', 'date' => '2020-01-02 03:04:05'),
array('id' => 2, 'title' => 'Undated', 'date' => NULL),
)));
$GLOBALS['num_stories'] = 5;
$page = display_stories();
$this->assertSame(1, substr_count($page, '<time '));
$this->assertStringContainsString('<dd class="date"></dd>', $page);
$this->assertStringContainsString('<dd class="date"></dd>', display_stories('2'));
}
public function testHiddenStoriesAreLeftOutForVisitors(): void {
$this->assertStringNotContainsString('Picture', display_stories());
}
public function testEditorsSeeHiddenStoriesMarkedAndEditLinks(): void {
$this->asEditor();
$page = display_stories();
$this->assertStringContainsString('<span class="right red">[hidden]</span>', $page);
$this->assertStringContainsString('[<a href="/publish/edit?id=3&amp;queue=0">edit</a>]', $page);
}
public function testImagesAreServedByDisplay(): void {
$this->asEditor();
$this->assertStringContainsString('<img src="/display?id=3" alt="Picture" />', display_stories());
}
public function testEditableListLinksTitlesToTheEditor(): void {
$this->asEditor();
$GLOBALS['editable'] = TRUE;
$this->request(array('queue' => '1'));
$page = display_stories();
$this->assertStringContainsString('<a href="/publish/edit?id=20&amp;queue=1">Waiting</a>', $page);
$this->assertStringNotContainsString('[<a href', $page);
}
public function testEditableImagesKeepTheQueue(): void {
$this->asEditor();
$GLOBALS['editable'] = TRUE;
$page = display_stories('3');
$this->assertStringContainsString('<img src="/display?id=3&amp;queue=0" alt="Picture" />', $page);
}
public function testOneStoryHasNoPager(): void {
$page = display_stories('2');
$this->assertSame(1, substr_count($page, '<li class="box">'));
$this->assertStringNotContainsString('class="pager"', $page);
}
public function testSeveralStoriesHaveAPager(): void {
$this->assertStringContainsString('<div class="pager">', display_stories());
}
public function testNoStories(): void {
$page = display_stories('99');
$this->assertStringContainsString('<p>No articles found.</p>', $page);
$this->assertStringNotContainsString('Try searching again', $page);
}
public function testNoSearchResults(): void {
$this->request(array('search' => 'nothing like this'));
$page = display_stories();
$this->assertStringContainsString('<p>No articles found.</p>', $page);
$this->assertStringContainsString('Try searching again', $page);
}
public function testPreviewShowsThePostedStoryWithoutLinks(): void {
$GLOBALS['action'] = 'preview';
$this->request(array(), array('title' => '<b>Mine</b>', 'author' => 'Me', 'story' => '<p>My <i>story</i></p><script>x()</script>'));
$page = display_stories();
$this->assertStringContainsString('<h3 class="articletitle">&lt;b&gt;Mine&lt;/b&gt;</h3>', $page);
$this->assertStringContainsString('<dd class="date">Awaiting posting</dd>', $page);
$this->assertStringContainsString('<p>My <i>story</i></p>', $page);
$this->assertStringNotContainsString('x()', $page);
}
// HTML Purifier needs seconds for a few megabytes, so a posted story over the limit is not shown
public function testPreviewDoesNotShowATooLongStory(): void {
$GLOBALS['action'] = 'preview';
$this->request(array(), array('title' => 'Long', 'author' => 'Me', 'story' => '<p><b>x</b></p>' . str_repeat('a', 65536)));
$page = display_stories();
$this->assertStringContainsString('<p>The story is too long to show.</p>', $page);
$this->assertStringNotContainsString('<b>x</b>', $page);
}
public function testPreviewShowsAPendingImage(): void {
$GLOBALS['action'] = 'preview';
$GLOBALS['file_src'] = '/display?pending="><script>';
$this->request(array(), array('title' => 'Pic', 'author' => 'Me'));
$this->assertStringContainsString('<img src="/display?pending=&quot;&gt;&lt;script&gt;" alt="Pic" />', display_stories());
}
public function testVisitorSubmitShowsTheirStory(): void {
$GLOBALS['action'] = 'submit';
$this->request(array(), array('title' => 'Sent', 'author' => 'Me', 'story' => '<p>Done</p>'));
$page = display_stories();
$this->assertMatchesRegularExpression('/<dd class="date">Posted \d{4}-\d\d-\d\d \d\d:\d\d<\/dd>/', $page);
$this->assertStringContainsString('<h3 class="articletitle">Sent</h3>', $page);
}
public function testVisitorSeesTheImageTheySubmittedFromTheQueue(): void {
$GLOBALS['action'] = 'submit';
$_SESSION['allow_queue_image'] = '20';
$this->request(array(), array('title' => 'Sent', 'author' => 'Me', 'uploaded' => 'yes'));
$this->assertStringContainsString('<img src="/display?id=20" alt="Sent" />', display_stories());
}
// An editor's submit saves to the queue, and the page shows the saved row
public function testEditorSubmitShowsTheSavedStoryFromTheQueue(): void {
$this->asEditor();
$GLOBALS['action'] = 'submit';
$page = display_stories('20');
$this->assertStringContainsString('Waiting', $page);
$this->assertStringContainsString('<p>No articles found.</p>', display_stories('2'));
}
}