113 lines
5.0 KiB
PHP
113 lines
5.0 KiB
PHP
<?php
|
|
namespace Xxx\Tests\Pages;
|
|
|
|
use Xxx\Tests\Support\PageTestCase;
|
|
|
|
// The public pages: the front page, the archive, a story and about
|
|
class FrontPagesTest extends PageTestCase {
|
|
protected function setUp(): void {
|
|
parent::setUp();
|
|
$this->setTables(array('xxx' => array(
|
|
array('id' => 1, 'title' => 'Newest', 'author' => 'Ann', 'date' => '2021-01-03 10:00:00', 'story' => '<p>First <em>story</em>.</p>'),
|
|
array('id' => 2, 'title' => 'Middle', 'author' => 'Bo', 'date' => '2021-01-02 10:00:00', 'story' => '<p onclick="x()">Second.</p>'),
|
|
array('id' => 3, 'title' => 'Secret', 'author' => 'Cy', 'date' => '2021-01-01 10:00:00', 'story' => '<p>Hidden.</p>', 'hidden' => '1'),
|
|
)));
|
|
}
|
|
|
|
public function testFrontPageListsTheVisibleStories(): void {
|
|
$page = $this->get('/');
|
|
$this->assertSame(200, $page['status']);
|
|
$this->assertStringContainsString('<a href="/article?id=1">Newest</a>', $page['body']);
|
|
$this->assertStringContainsString('<a href="/article?id=2">Middle</a>', $page['body']);
|
|
$this->assertStringNotContainsString('Secret', $page['body']);
|
|
$this->assertStringNotContainsString('onclick', $page['body']);
|
|
$this->assertStringEndsWith("</html>\n", $page['body']);
|
|
}
|
|
|
|
public function testPagesAreNotCached(): void {
|
|
$page = $this->get('/');
|
|
$this->assertStringContainsString('no-store', implode(', ', $page['headers']['cache-control']));
|
|
}
|
|
|
|
public function testTheSessionCookieIsSecure(): void {
|
|
$cookie = $this->header($this->get('/'), 'Set-Cookie');
|
|
$this->assertMatchesRegularExpression('/^PHPSESSID=[0-9a-z,-]+;/', $cookie);
|
|
foreach (array('path=/', 'domain=.site.test', 'secure', 'HttpOnly', 'SameSite=Lax') as $flag)
|
|
$this->assertStringContainsString("; $flag", $cookie);
|
|
}
|
|
|
|
// Another site cannot show a page in a hidden frame to trick an editor into a click
|
|
public function testNoPageCanBeFramed(): void {
|
|
$paths = array('/', '/article', '/about', '/publish', '/publish/login');
|
|
$this->loginAs();
|
|
$paths = array_merge($paths, array('/publish/edit', '/publish/addeditor'));
|
|
foreach ($paths as $path) {
|
|
$page = $this->get($path);
|
|
$this->assertSame('DENY', $this->header($page, 'X-Frame-Options'), $path);
|
|
$this->assertSame("frame-ancestors 'none'", $this->header($page, 'Content-Security-Policy'), $path);
|
|
}
|
|
$this->assertSame('DENY', $this->header($this->get('/', array('X-Test-Plain' => '1')), 'X-Frame-Options'));
|
|
}
|
|
|
|
public function testPlainHttpStartsNoSession(): void {
|
|
$page = $this->get('/', array('X-Test-Plain' => '1'));
|
|
$this->assertSame(200, $page['status']);
|
|
$this->assertArrayNotHasKey('set-cookie', $page['headers']);
|
|
}
|
|
|
|
public function testNoAnalyticsOrEditorLinksForVisitors(): void {
|
|
$body = $this->get('/')['body'];
|
|
$this->assertStringNotContainsString('google-analytics', $body);
|
|
$this->assertStringNotContainsString('/publish/logout', $body);
|
|
$this->assertStringNotContainsString('/publish/addeditor', $body);
|
|
}
|
|
|
|
public function testEditorsSeeHiddenStoriesAndTheirLinks(): void {
|
|
$token = $this->loginAs();
|
|
$body = $this->get('/')['body'];
|
|
$this->assertStringContainsString('Secret', $body);
|
|
$this->assertStringContainsString('<a href="/publish/logout?token=' . $token . '">Logout</a>', $body);
|
|
$this->assertStringContainsString('<a href="/publish/addeditor">Add editor</a>', $body);
|
|
}
|
|
|
|
public function testTheArticlePageShowsOneStory(): void {
|
|
$body = $this->get('/article?id=1')['body'];
|
|
$this->assertStringContainsString('<p>First <em>story</em>.</p>', $body);
|
|
$this->assertStringNotContainsString('Middle', $body);
|
|
}
|
|
|
|
public function testAHiddenStoryIsNotShown(): void {
|
|
$body = $this->get('/article?id=3')['body'];
|
|
$this->assertStringNotContainsString('Hidden.', $body);
|
|
}
|
|
|
|
public function testSearchFindsStories(): void {
|
|
$body = $this->get('/article?search=second')['body'];
|
|
$this->assertStringContainsString('Middle', $body);
|
|
$this->assertStringNotContainsString('Newest', $body);
|
|
$this->assertSame(array('%second%'), array_slice($this->queries('/LIKE/')[0]['params'], 0, 1));
|
|
}
|
|
|
|
public function testTheSearchTermIsEscaped(): void {
|
|
$body = $this->get('/article?search=' . rawurlencode('"><script>x</script>'))['body'];
|
|
$this->assertStringNotContainsString('<script>x</script>', $body);
|
|
}
|
|
|
|
public function testThePageRemembersWhereTheVisitorWas(): void {
|
|
$this->get('/article?id=2');
|
|
$this->assertSame('/article?id=2', $this->session()['referrer']);
|
|
}
|
|
|
|
public function testTheAboutPageLoads(): void {
|
|
$page = $this->get('/about');
|
|
$this->assertSame(200, $page['status']);
|
|
$this->assertStringContainsString('</html>', $page['body']);
|
|
// The webmaster's address, at the host of SITE_URL, hidden from harvesters
|
|
$this->assertStringContainsString('<a href="' . hidden_email('mailto:webmaster@site.test') . '">email us</a>', $page['body']);
|
|
}
|
|
|
|
public function testTheTestsAreNotServed(): void {
|
|
$this->assertSame(404, $this->get('/tests/php/fixtures/test.env')['status']);
|
|
}
|
|
}
|