Same-site redirects are now relative paths, and a saved page on another site is ignored. The HTTP to HTTPS redirect takes its host from the new SITE_URL setting, and without it the pages refuse plain HTTP.
122 lines
6.6 KiB
PHP
122 lines
6.6 KiB
PHP
<?php
|
|
namespace Xxx\Tests\Pages;
|
|
|
|
use Xxx\Tests\Support\PageTestCase;
|
|
|
|
// Sending a story from publish/ as a visitor
|
|
class SubmitTest extends PageTestCase {
|
|
protected function setUp(): void {
|
|
parent::setUp();
|
|
$this->setTables(array('xxx' => array(array('id' => 1, 'title' => 'Live'))));
|
|
}
|
|
|
|
private function story(array $fields = array()): array {
|
|
return $fields + array('title' => 'My story', 'author' => 'Vi', 'email' => 'vi@example.org',
|
|
'story' => '<p>Once -- upon a "time"<script>x()</script>.</p>');
|
|
}
|
|
|
|
public function testPlainHttpIsSentToHttps(): void {
|
|
$this->assertRedirect('https://site.test/publish', $this->get('/publish', array('X-Test-Plain' => '1')));
|
|
}
|
|
|
|
public function testTheFormHasATokenAndTheCaptcha(): void {
|
|
$page = $this->get('/publish');
|
|
$this->assertSame(200, $page['status']);
|
|
$this->assertSame($this->session()['csrf_token'], $this->csrfToken($page['body']));
|
|
$this->assertStringContainsString('<div class="g-recaptcha" data-sitekey="test-site-key"></div>', $page['body']);
|
|
$this->assertStringContainsString('https://www.google.com/recaptcha/api.js', $page['body']);
|
|
$this->assertStringContainsString('<script type="text/javascript" src="../publish/editor.js"></script>', $page['body']);
|
|
}
|
|
|
|
public function testTheImageTabKeepsTheSpaceOfTheNote(): void {
|
|
$html = new \DOMDocument();
|
|
$html->loadHTML($this->get('/publish')['body'], LIBXML_NOERROR);
|
|
$xpath = new \DOMXPath($html);
|
|
$note = $xpath->query('//div[@id="textparent"]/div[@class="note"]');
|
|
$spacer = $xpath->query('//div[@id="uploadparent"]/div[@class="note spacer"][@aria-hidden="true"]');
|
|
$this->assertCount(1, $note);
|
|
$this->assertCount(1, $spacer);
|
|
$this->assertSame($note[0]->textContent, $spacer[0]->textContent);
|
|
$this->assertCount(1, $xpath->query('//div[@id="uploadparent"]/div[@class="upload"]//input[@id="upload"]'));
|
|
// Both tabs sit in the same column
|
|
$this->assertCount(2, $xpath->query('//div[@class="textarea rightcolumn"]/div[@id="textparent" or @id="uploadparent"]'));
|
|
}
|
|
|
|
public function testEditorsGetNoCaptcha(): void {
|
|
$this->loginAs();
|
|
$body = $this->get('/publish')['body'];
|
|
$this->assertStringNotContainsString('recaptcha', $body);
|
|
}
|
|
|
|
public function testPreviewThenSubmitAddsTheStoryToTheQueue(): void {
|
|
$token = $this->csrfToken($this->get('/publish')['body']);
|
|
$preview = $this->post('/publish', $this->story(array('action' => 'preview', 'csrf_token' => $token, 'g-recaptcha-response' => 'pass')));
|
|
$this->assertStringContainsString('Please review your submission.', $preview['body']);
|
|
// The preview shows the purified story; the typography comes when it is saved
|
|
$this->assertStringContainsString('<p>Once -- upon a "time".</p>', $preview['body']);
|
|
$this->assertStringContainsString('<button type="submit" id="submit" name="action" value="submit">', $preview['body']);
|
|
// The solved captcha lasts until the story is saved
|
|
$this->assertStringNotContainsString('g-recaptcha', $preview['body']);
|
|
$this->assertSame(array(), $this->queries('/^INSERT/'));
|
|
|
|
$this->post('/publish', $this->story(array('action' => 'submit', 'csrf_token' => $token)));
|
|
$tables = $this->tables();
|
|
$this->assertCount(1, $tables['xxx']);
|
|
$this->assertCount(1, $tables['queue']);
|
|
$row = $tables['queue'][0];
|
|
$this->assertSame(array('My story', 'Vi', 'vi@example.org', '<p>Once — upon a “time”.</p>', 'original author', 0),
|
|
array($row['title'], $row['author'], $row['email'], $row['story'], $row['editor'], $row['hidden']));
|
|
$session = $this->session();
|
|
$this->assertArrayNotHasKey('captcha_ok', $session);
|
|
$this->assertSame($row['id'], (string)$session['allow_queue_image']);
|
|
|
|
$mails = $this->mails();
|
|
$this->assertCount(1, $mails);
|
|
$this->assertSame('New submission: My story', $mails[0]['subject']);
|
|
$this->assertStringContainsString('Once — upon a “time”.', $mails[0]['body']);
|
|
}
|
|
|
|
public function testVisitorsCannotPostOrOverwrite(): void {
|
|
$token = $this->csrfToken($this->get('/publish')['body']);
|
|
$this->post('/publish', $this->story(array('action' => 'post', 'id' => '1', 'hidden' => 'on', 'editor' => 'ed',
|
|
'comments' => 'x', 'csrf_token' => $token, 'g-recaptcha-response' => 'pass')));
|
|
$tables = $this->tables();
|
|
$this->assertSame('Live', $tables['xxx'][0]['title']);
|
|
$this->assertCount(1, $tables['xxx']);
|
|
$this->assertCount(1, $tables['queue']);
|
|
$this->assertSame(array('original author', 0, ''), array($tables['queue'][0]['editor'], $tables['queue'][0]['hidden'], $tables['queue'][0]['comments']));
|
|
}
|
|
|
|
public function testAPostWithoutTheTokenOnlyGetsAPreview(): void {
|
|
$this->get('/publish');
|
|
$page = $this->post('/publish', $this->story(array('action' => 'submit', 'csrf_token' => 'wrong', 'g-recaptcha-response' => 'pass')));
|
|
$this->assertStringContainsString('Your session has expired. Please check your story, then send it again.', $page['body']);
|
|
$this->assertSame(array(), $this->queries('/^INSERT/'));
|
|
$this->assertSame(array(), $this->mails());
|
|
}
|
|
|
|
public function testAFailedCaptchaStopsTheStory(): void {
|
|
$token = $this->csrfToken($this->get('/publish')['body']);
|
|
$page = $this->post('/publish', $this->story(array('action' => 'submit', 'csrf_token' => $token, 'g-recaptcha-response' => 'fail')));
|
|
$this->assertStringContainsString('Please complete the captcha.', $page['body']);
|
|
$this->assertStringContainsString('g-recaptcha', $page['body']);
|
|
$this->assertSame(array(), $this->queries('/^INSERT/'));
|
|
}
|
|
|
|
public function testMissingFieldsAreShown(): void {
|
|
$token = $this->csrfToken($this->get('/publish')['body']);
|
|
$page = $this->post('/publish', array('action' => 'submit', 'csrf_token' => $token, 'g-recaptcha-response' => 'pass', 'story' => '<p>x</p>'));
|
|
$this->assertStringContainsString('<li>You have not submitted an author.</li>', $page['body']);
|
|
$this->assertStringContainsString('<label class="red" for="title">', $page['body']);
|
|
$this->assertSame(array(), $this->queries('/^INSERT/'));
|
|
}
|
|
|
|
public function testFieldsAreEscapedInTheForm(): void {
|
|
$token = $this->csrfToken($this->get('/publish')['body']);
|
|
$page = $this->post('/publish', $this->story(array('action' => 'preview', 'csrf_token' => $token, 'g-recaptcha-response' => 'pass',
|
|
'title' => '"><script>alert(1)</script>')));
|
|
$this->assertStringNotContainsString('<script>alert(1)</script>', $page['body']);
|
|
$this->assertStringContainsString('value=""><script>alert(1)</script>"', $page['body']);
|
|
}
|
|
}
|