silverstripe-cms/tests/model/SiteTreeBrokenLinksTest.php
Mateusz Uzdowski 2ba1c46bc8 API Change broken link hihglighting to write to database.
Before it would be applied on the fly during the rendering of the
HtmlEditorField, and only be written to the database during the
subsequent write.

We just shift the behaviour to apply just-in-time.
2014-08-15 12:29:26 +12:00

312 lines
11 KiB
PHP

<?php
/**
* @package cms
* @subpackage tests
*/
class SiteTreeBrokenLinksTest extends SapphireTest {
protected static $fixture_file = 'SiteTreeBrokenLinksTest.yml';
public function testBrokenLinksBetweenPages() {
$obj = $this->objFromFixture('Page','content');
$obj->Content = '<a href="[sitetree_link,id=3423423]">this is a broken link</a>';
$obj->syncLinkTracking();
$this->assertTrue($obj->HasBrokenLink, 'Page has a broken link');
$obj->Content = '<a href="[sitetree_link,id=' . $this->idFromFixture('Page','about') .']">this is not a broken link</a>';
$obj->syncLinkTracking();
$this->assertFalse($obj->HasBrokenLink, 'Page does NOT have a broken link');
}
public function testBrokenAnchorBetweenPages() {
$obj = $this->objFromFixture('Page','content');
$target = $this->objFromFixture('Page', 'about');
$obj->Content = "<a href=\"[sitetree_link,id={$target->ID}]#no-anchor-here\">this is a broken link</a>";
$obj->syncLinkTracking();
$this->assertTrue($obj->HasBrokenLink, 'Page has a broken link');
$obj->Content = "<a href=\"[sitetree_link,id={$target->ID}]#yes-anchor-here\">this is not a broken link</a>";
$obj->syncLinkTracking();
$this->assertFalse($obj->HasBrokenLink, 'Page does NOT have a broken link');
}
public function testBrokenVirtualPages() {
$obj = $this->objFromFixture('Page','content');
$vp = new VirtualPage();
$vp->CopyContentFromID = $obj->ID;
$vp->syncLinkTracking();
$this->assertFalse($vp->HasBrokenLink, 'Working virtual page is NOT marked as broken');
$vp->CopyContentFromID = 12345678;
$vp->syncLinkTracking();
$this->assertTrue($vp->HasBrokenLink, 'Broken virtual page IS marked as such');
}
public function testBrokenInternalRedirectorPages() {
$obj = $this->objFromFixture('Page','content');
$rp = new RedirectorPage();
$rp->RedirectionType = 'Internal';
$rp->LinkToID = $obj->ID;
$rp->syncLinkTracking();
$this->assertFalse($rp->HasBrokenLink, 'Working redirector page is NOT marked as broken');
$rp->LinkToID = 12345678;
$rp->syncLinkTracking();
$this->assertTrue($rp->HasBrokenLink, 'Broken redirector page IS marked as such');
}
public function testDeletingFileMarksBackedPagesAsBroken() {
// Test entry
$file = new File();
$file->Filename = 'test-file.pdf';
$file->write();
$obj = $this->objFromFixture('Page','content');
$obj->Content = sprintf(
'<p><a href="[file_link,id=%d]">Working Link</a></p>',
$file->ID
);
$obj->write();
$this->assertTrue($obj->doPublish());
// Confirm that it isn't marked as broken to begin with
$obj->flushCache();
$obj = DataObject::get_by_id("SiteTree", $obj->ID);
$this->assertEquals(0, $obj->HasBrokenFile);
$liveObj = Versioned::get_one_by_stage("SiteTree", "Live","\"SiteTree\".\"ID\" = $obj->ID");
$this->assertEquals(0, $liveObj->HasBrokenFile);
// Delete the file
$file->delete();
// Confirm that it is marked as broken in both stage and live
$obj->flushCache();
$obj = DataObject::get_by_id("SiteTree", $obj->ID);
$this->assertEquals(1, $obj->HasBrokenFile);
$liveObj = Versioned::get_one_by_stage("SiteTree", "Live", "\"SiteTree\".\"ID\" = $obj->ID");
$this->assertEquals(1, $liveObj->HasBrokenFile);
}
public function testDeletingMarksBackLinkedPagesAsBroken() {
$this->logInWithPermission('ADMIN');
// Set up two published pages with a link from content -> about
$linkDest = $this->objFromFixture('Page','about');
$linkDest->doPublish();
$linkSrc = $this->objFromFixture('Page','content');
$linkSrc->Content = "<p><a href=\"[sitetree_link,id=$linkDest->ID]\">about us</a></p>";
$linkSrc->write();
$linkSrc->doPublish();
// Confirm no broken link
$this->assertEquals(0, (int)$linkSrc->HasBrokenLink);
$this->assertEquals(0, DB::query("SELECT \"HasBrokenLink\" FROM \"SiteTree_Live\"
WHERE \"ID\" = $linkSrc->ID")->value());
// Delete page from draft
$linkDestID = $linkDest->ID;
$linkDest->delete();
// Confirm draft has broken link, and published doesn't
$linkSrc->flushCache();
$linkSrc = $this->objFromFixture('Page', 'content');
$this->assertEquals(1, (int)$linkSrc->HasBrokenLink);
$this->assertEquals(0, DB::query("SELECT \"HasBrokenLink\" FROM \"SiteTree_Live\"
WHERE \"ID\" = $linkSrc->ID")->value());
// Delete from live
$linkDest = Versioned::get_one_by_stage("SiteTree", "Live", "\"SiteTree\".\"ID\" = $linkDestID");
$linkDest->doDeleteFromLive();
// Confirm both draft and published have broken link
$linkSrc->flushCache();
$linkSrc = $this->objFromFixture('Page', 'content');
$this->assertEquals(1, (int)$linkSrc->HasBrokenLink);
$this->assertEquals(1, DB::query("SELECT \"HasBrokenLink\" FROM \"SiteTree_Live\"
WHERE \"ID\" = $linkSrc->ID")->value());
}
public function testPublishingSourceBeforeDestHasBrokenLink() {
$this->logInWithPermission('ADMIN');
// Set up two draft pages with a link from content -> about
$linkDest = $this->objFromFixture('Page','about');
// Ensure that it's not on the published site
$linkDest->doDeleteFromLive();
$linkSrc = $this->objFromFixture('Page','content');
$linkSrc->Content = "<p><a href=\"[sitetree_link,id=$linkDest->ID]\">about us</a></p>";
$linkSrc->write();
// Publish the source of the link, while the dest is still unpublished.
$linkSrc->doPublish();
// Verify that the link isn't broken on draft but is broken on published
$this->assertEquals(0, (int)$linkSrc->HasBrokenLink);
$this->assertEquals(1, DB::query("SELECT \"HasBrokenLink\" FROM \"SiteTree_Live\"
WHERE \"ID\" = $linkSrc->ID")->value());
}
public function testRestoreFixesBrokenLinks() {
// Create page and virtual page
$p = new Page();
$p->Title = "source";
$p->write();
$pageID = $p->ID;
$this->assertTrue($p->doPublish());
// Content links are one kind of link to pages
$p2 = new Page();
$p2->Title = "regular link";
$p2->Content = "<a href=\"[sitetree_link,id=$p->ID]\">test</a>";
$p2->write();
$this->assertTrue($p2->doPublish());
// Virtual pages are another
$vp = new VirtualPage();
$vp->CopyContentFromID = $p->ID;
$vp->write();
// Redirector links are a third
$rp = new RedirectorPage();
$rp->Title = "redirector";
$rp->LinkType = 'Internal';
$rp->LinkToID = $p->ID;
$rp->write();
$this->assertTrue($rp->doPublish());
// Confirm that there are no broken links to begin with
$this->assertFalse($p2->HasBrokenLink);
$this->assertFalse($vp->HasBrokenLink);
$this->assertFalse($rp->HasBrokenLink);
// Unpublish the source page, confirm that the page 2 and RP has a broken link on published
$p->doUnpublish();
$p2Live = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $p2->ID);
$rpLive = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $rp->ID);
$this->assertEquals(1, $p2Live->HasBrokenLink);
$this->assertEquals(1, $rpLive->HasBrokenLink);
// Delete the source page, confirm that the VP, RP and page 2 have broken links on draft
$p->delete();
$vp->flushCache();
$vp = DataObject::get_by_id('SiteTree', $vp->ID);
$p2->flushCache();
$p2 = DataObject::get_by_id('SiteTree', $p2->ID);
$rp->flushCache();
$rp = DataObject::get_by_id('SiteTree', $rp->ID);
$this->assertEquals(1, $p2->HasBrokenLink);
$this->assertEquals(1, $vp->HasBrokenLink);
$this->assertEquals(1, $rp->HasBrokenLink);
// Restore the page to stage, confirm that this fixes the links
$p = Versioned::get_latest_version('SiteTree', $pageID);
$p->doRestoreToStage();
$p2->flushCache();
$p2 = DataObject::get_by_id('SiteTree', $p2->ID);
$vp->flushCache();
$vp = DataObject::get_by_id('SiteTree', $vp->ID);
$rp->flushCache();
$rp = DataObject::get_by_id('SiteTree', $rp->ID);
$this->assertFalse((bool)$p2->HasBrokenLink);
$this->assertFalse((bool)$vp->HasBrokenLink);
$this->assertFalse((bool)$rp->HasBrokenLink);
// Publish and confirm that the p2 and RP broken links are fixed on published
$this->assertTrue($p->doPublish());
$p2Live = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $p2->ID);
$rpLive = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $rp->ID);
$this->assertFalse((bool)$p2Live->HasBrokenLink);
$this->assertFalse((bool)$rpLive->HasBrokenLink);
}
public function testRevertToLiveFixesBrokenLinks() {
// Create page and virutal page
$p = new Page();
$p->Title = "source";
$p->write();
$pageID = $p->ID;
$this->assertTrue($p->doPublish());
// Content links are one kind of link to pages
$p2 = new Page();
$p2->Title = "regular link";
$p2->Content = "<a href=\"[sitetree_link,id=$p->ID]\">test</a>";
$p2->write();
$this->assertTrue($p2->doPublish());
// Virtual pages are another
$vp = new VirtualPage();
$vp->CopyContentFromID = $p->ID;
$vp->write();
// Redirector links are a third
$rp = new RedirectorPage();
$rp->Title = "redirector";
$rp->LinkType = 'Internal';
$rp->LinkToID = $p->ID;
$rp->write();
$this->assertTrue($rp->doPublish());
// Confirm that there are no broken links to begin with
$this->assertFalse($p2->HasBrokenLink);
$this->assertFalse($vp->HasBrokenLink);
$this->assertFalse($rp->HasBrokenLink);
// Delete from draft and confirm that broken links are marked
$pID = $p->ID;
$p->delete();
$vp->flushCache();
$vp = DataObject::get_by_id('SiteTree', $vp->ID);
$p2->flushCache();
$p2 = DataObject::get_by_id('SiteTree', $p2->ID);
$rp->flushCache();
$rp = DataObject::get_by_id('SiteTree', $rp->ID);
$this->assertEquals(1, $p2->HasBrokenLink);
$this->assertEquals(1, $vp->HasBrokenLink);
$this->assertEquals(1, $rp->HasBrokenLink);
// Call doRevertToLive and confirm that broken links are restored
$pLive = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $pID);
$pLive->doRevertToLive();
$p2->flushCache();
$p2 = DataObject::get_by_id('SiteTree', $p2->ID);
$vp->flushCache();
$vp = DataObject::get_by_id('SiteTree', $vp->ID);
$rp->flushCache();
$rp = DataObject::get_by_id('SiteTree', $rp->ID);
$this->assertFalse((bool)$p2->HasBrokenLink);
$this->assertFalse((bool)$vp->HasBrokenLink);
$this->assertFalse((bool)$rp->HasBrokenLink);
}
public function testBrokenAnchorLinksInAPage() {
$obj = $this->objFromFixture('Page','content');
$origContent = $obj->Content;
$obj->Content = $origContent . '<a href="#no-anchor-here">this links to a non-existent in-page anchor or skiplink</a>';
$obj->syncLinkTracking();
$this->assertTrue($obj->HasBrokenLink, 'Page has a broken anchor/skiplink');
$obj->Content = $origContent . '<a href="#yes-anchor-here">this links to an existent in-page anchor/skiplink</a>';
$obj->syncLinkTracking();
$this->assertFalse($obj->HasBrokenLink, 'Page doesn\'t have a broken anchor or skiplink');
}
}