Source of file TkiRequirementsTest.php
Size: 67,693 Bytes - Last Modified: 2021-12-23T10:52:21+00:00
/var/www/docs.ssmods.com/process/src/tests/TkiRequirementsTest.php
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747 | <?php /** * This class mostly duplicates the RequirementsTest class to test * the TkiRequirements_Backend class, to ensure compatibility. * Additional methods are added to test the features made available by * TkiRequirements_Backend, such as prioritisation and specifying script location. * @package tkirequirements * @subpackage tests * */ class TkiRequirementsTest extends RequirementsTest { /* * ------------------------------------------------------------------------- * Tests for parent methods * ------------------------------------------------------------------------- */ public function testExternalUrls() { $backend = new TkiRequirements_Backend; $backend->set_combined_files_enabled(true); $backend->javascript('http://www.mydomain.com/test.js'); $backend->javascript('https://www.mysecuredomain.com/test.js'); $backend->javascript('//scheme-relative.example.com/test.js'); $backend->css('http://www.mydomain.com/test.css'); $backend->css('https://www.mysecuredomain.com/test.css'); $backend->css('//scheme-relative.example.com/test.css'); $html = $backend->includeInHTML(false, self::$html_template); $this->assertTrue( (strpos($html, 'http://www.mydomain.com/test.js') !== false), 'Load external javascript URL' ); $this->assertTrue( (strpos($html, 'https://www.mysecuredomain.com/test.js') !== false), 'Load external secure javascript URL' ); $this->assertTrue( (strpos($html, '//scheme-relative.example.com/test.js') !== false), 'Load external scheme-relative javascript URL' ); $this->assertTrue( (strpos($html, 'http://www.mydomain.com/test.css') !== false), 'Load external CSS URL' ); $this->assertTrue( (strpos($html, 'https://www.mysecuredomain.com/test.css') !== false), 'Load external secure CSS URL' ); $this->assertTrue( (strpos($html, '//scheme-relative.example.com/test.css') !== false), 'Load scheme-relative CSS URL' ); } protected function setupCombinedRequirements($backend) { $basePath = $this->getCurrentRelativePath(); $backend->clear(); $backend->setCombinedFilesFolder('assets'); // clearing all previously generated requirements (just in case) $backend->clear_combined_files(); $backend->delete_combined_files('RequirementsTest_bc.js'); // require files normally (e.g. called from a FormField instance) $backend->javascript($basePath . '/files/RequirementsTest_a.js'); $backend->javascript($basePath . '/files/RequirementsTest_b.js'); $backend->javascript($basePath . '/files/RequirementsTest_c.js'); // require two of those files as combined includes $backend->combine_files( 'RequirementsTest_bc.js', array( $basePath . '/files/RequirementsTest_b.js', $basePath . '/files/RequirementsTest_c.js' ) ); } protected function setupCombinedNonrequiredRequirements($backend) { $basePath = $this->getCurrentRelativePath(); $backend->clear(); $backend->setCombinedFilesFolder('assets'); // clearing all previously generated requirements (just in case) $backend->clear_combined_files(); $backend->delete_combined_files('RequirementsTest_bc.js'); // require files as combined includes $backend->combine_files( 'RequirementsTest_bc.js', array( $basePath . '/files/RequirementsTest_b.js', $basePath . '/files/RequirementsTest_c.js' ) ); } public function testCombinedJavascript() { $backend = new TkiRequirements_Backend; $backend->set_combined_files_enabled(true); $backend->setCombinedFilesFolder('assets'); $this->setupCombinedRequirements($backend); $combinedFilePath = Director::baseFolder() . '/assets/' . 'RequirementsTest_bc.js'; $html = $backend->includeInHTML(false, self::$html_template); /* COMBINED JAVASCRIPT FILE IS INCLUDED IN HTML HEADER */ $this->assertTrue((bool)preg_match('/src=".*\/RequirementsTest_bc\.js/', $html), 'combined javascript file is included in html header'); /* COMBINED JAVASCRIPT FILE EXISTS */ $this->assertTrue(file_exists($combinedFilePath), 'combined javascript file exists'); /* COMBINED JAVASCRIPT HAS CORRECT CONTENT */ $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false), 'combined javascript has correct content'); $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('c')") !== false), 'combined javascript has correct content'); /* COMBINED FILES ARE NOT INCLUDED TWICE */ $this->assertFalse((bool)preg_match('/src=".*\/RequirementsTest_b\.js/', $html), 'combined files are not included twice'); $this->assertFalse((bool)preg_match('/src=".*\/RequirementsTest_c\.js/', $html), 'combined files are not included twice'); /* NORMAL REQUIREMENTS ARE STILL INCLUDED */ $this->assertTrue((bool)preg_match('/src=".*\/RequirementsTest_a\.js/', $html), 'normal requirements are still included'); $backend->delete_combined_files('RequirementsTest_bc.js'); // Then do it again, this time not requiring the files beforehand $backend = new TkiRequirements_Backend; $backend->set_combined_files_enabled(true); $backend->setCombinedFilesFolder('assets'); $this->setupCombinedNonrequiredRequirements($backend); $combinedFilePath = Director::baseFolder() . '/assets/' . 'RequirementsTest_bc.js'; $html = $backend->includeInHTML(false, self::$html_template); /* COMBINED JAVASCRIPT FILE IS INCLUDED IN HTML HEADER */ $this->assertTrue((bool)preg_match('/src=".*\/RequirementsTest_bc\.js/', $html), 'combined javascript file is included in html header'); /* COMBINED JAVASCRIPT FILE EXISTS */ $this->assertTrue(file_exists($combinedFilePath), 'combined javascript file exists'); /* COMBINED JAVASCRIPT HAS CORRECT CONTENT */ $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false), 'combined javascript has correct content'); $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('c')") !== false), 'combined javascript has correct content'); /* COMBINED FILES ARE NOT INCLUDED TWICE */ $this->assertFalse((bool)preg_match('/src=".*\/RequirementsTest_b\.js/', $html), 'combined files are not included twice'); $this->assertFalse((bool)preg_match('/src=".*\/RequirementsTest_c\.js/', $html), 'combined files are not included twice'); $backend->delete_combined_files('RequirementsTest_bc.js'); } public function testCombinedCss() { $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend; $backend->set_combined_files_enabled(true); $backend->combine_files( 'print.css', array( $basePath . '/files/RequirementsTest_print_a.css', $basePath . '/files/RequirementsTest_print_b.css' ), 'print' ); $html = $backend->includeInHTML(false, self::$html_template); $this->assertTrue((bool)preg_match('/href=".*\/print\.css/', $html), 'Print stylesheets have been combined.'); $this->assertTrue((bool)preg_match( '/media="print/', $html), 'Combined print stylesheet retains the media parameter' ); } public function testBlockedCombinedJavascript() { $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend; $backend->set_combined_files_enabled(true); $backend->setCombinedFilesFolder('assets'); $combinedFilePath = Director::baseFolder() . '/assets/' . 'RequirementsTest_bc.js'; /* BLOCKED COMBINED FILES ARE NOT INCLUDED */ $this->setupCombinedRequirements($backend); $backend->block('RequirementsTest_bc.js'); $backend->delete_combined_files('RequirementsTest_bc.js'); clearstatcache(); // needed to get accurate file_exists() results $html = $backend->includeInHTML(false, self::$html_template); $this->assertFalse((bool)preg_match('/src=".*\/RequirementsTest_bc\.js/', $html), 'blocked combined files are not included '); $backend->unblock('RequirementsTest_bc.js'); /* BLOCKED UNCOMBINED FILES ARE NOT INCLUDED */ $this->setupCombinedRequirements($backend); $backend->block($basePath .'/files/RequirementsTest_b.js'); $backend->delete_combined_files('RequirementsTest_bc.js'); clearstatcache(); // needed to get accurate file_exists() results $html = $backend->includeInHTML(false, self::$html_template); $this->assertFalse((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false), 'blocked uncombined files are not included'); $backend->unblock('RequirementsTest_b.js'); /* A SINGLE FILE CAN'T BE INCLUDED IN TWO COMBINED FILES */ $this->setupCombinedRequirements($backend); clearstatcache(); // needed to get accurate file_exists() results // This throws a notice-level error, so we prefix with @ @$backend->combine_files( 'RequirementsTest_ac.js', array( $basePath . '/files/RequirementsTest_a.js', $basePath . '/files/RequirementsTest_c.js' ) ); $combinedFiles = $backend->get_combine_files(); $this->assertEquals( array_keys($combinedFiles), array('RequirementsTest_bc.js'), "A single file can't be included in two combined files" ); $backend->delete_combined_files('RequirementsTest_bc.js'); } public function testArgsInUrls() { $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend; $backend->set_combined_files_enabled(true); $backend->javascript($basePath . '/files/RequirementsTest_a.js?test=1&test=2&test=3'); $backend->css($basePath . '/files/RequirementsTest_a.css?test=1&test=2&test=3'); $backend->delete_combined_files('RequirementsTest_bc.js'); $html = $backend->includeInHTML(false, self::$html_template); /* Javascript has correct path */ $this->assertTrue( (bool)preg_match('/src=".*\/RequirementsTest_a\.js\?m=\d\d+&test=1&test=2&test=3/',$html), 'javascript has correct path'); /* CSS has correct path */ $this->assertTrue( (bool)preg_match('/href=".*\/RequirementsTest_a\.css\?m=\d\d+&test=1&test=2&test=3/',$html), 'css has correct path'); } public function testRequirementsBackend() { $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend(); $backend->javascript($basePath . '/a.js'); $this->assertTrue(count($backend->get_javascript()) == 1, "There should be only 1 file included in required javascript."); $this->assertTrue(in_array($basePath . '/a.js', $backend->get_javascript()), "a.js should be included in required javascript."); $backend->javascript($basePath . '/b.js'); $this->assertTrue(count($backend->get_javascript()) == 2, "There should be 2 files included in required javascript."); $backend->block($basePath . '/a.js'); $this->assertTrue(count($backend->get_javascript()) == 1, "There should be only 1 file included in required javascript."); $this->assertFalse(in_array($basePath . '/a.js', $backend->get_javascript()), "a.js should not be included in required javascript after it has been blocked."); $this->assertTrue(in_array($basePath . '/b.js', $backend->get_javascript()), "b.js should be included in required javascript."); $backend->css($basePath . '/a.css'); $this->assertTrue(count($backend->get_css()) == 1, "There should be only 1 file included in required css."); $this->assertArrayHasKey($basePath . '/a.css', $backend->get_css(), "a.css should be in required css."); $backend->block($basePath . '/a.css'); $this->assertTrue(count($backend->get_css()) == 0, "There should be nothing in required css after file has been blocked."); } public function testConditionalTemplateRequire() { $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend(); $holder = Requirements::backend(); Requirements::set_backend($backend); $data = new ArrayData(array( 'FailTest' => true, )); $data->renderWith('TkiRequirementsTest_Conditionals'); $this->assertFileIncluded($backend, 'css', $basePath .'/files/RequirementsTest_a.css'); $this->assertFileIncluded($backend, 'js', array($basePath .'/files/RequirementsTest_b.js', $basePath .'/files/RequirementsTest_c.js')); $this->assertFileNotIncluded($backend, 'js', $basePath .'/files/RequirementsTest_a.js'); $this->assertFileNotIncluded($backend, 'css', array($basePath .'/files/RequirementsTest_b.css', $basePath .'/files/RequirementsTest_c.css')); $backend->clear(); $data = new ArrayData(array( 'FailTest' => false, )); $data->renderWith('TkiRequirementsTest_Conditionals'); $this->assertFileNotIncluded($backend, 'css', $basePath .'/files/RequirementsTest_a.css'); $this->assertFileNotIncluded($backend, 'js', array($basePath .'/files/RequirementsTest_b.js', $basePath .'/files/RequirementsTest_c.js')); $this->assertFileIncluded($backend, 'js', $basePath .'/files/RequirementsTest_a.js'); $this->assertFileIncluded($backend, 'css', array($basePath .'/files/RequirementsTest_b.css', $basePath .'/files/RequirementsTest_c.css')); Requirements::set_backend($holder); } public function testJsWriteToBody() { $backend = new TkiRequirements_Backend(); $backend->javascript('http://www.mydomain.com/test.js'); // Test matching with HTML5 <header> tags as well $template = '<html><head></head><body><header>My header</header><p>Body</p></body></html>'; $backend->set_write_js_to_body(false); $html = $backend->includeInHTML(false, $template); $this->assertContains('<head><script', $html); $backend->set_write_js_to_body(true); $html = $backend->includeInHTML(false, $template); $this->assertNotContains('<head><script', $html); $this->assertContains('</script></body>', $html); } public function testIncludedJsIsNotCommentedOut() { $template = '<html><head></head><body><!--<script>alert("commented out");</script>--></body></html>'; $backend = new TkiRequirements_Backend(); $backend->javascript($this->getCurrentRelativePath() . '/files/RequirementsTest_a.js'); $html = $backend->includeInHTML(false, $template); //wiping out commented-out html $html = preg_replace('/<!--(.*)-->/Uis', '', $html); $this->assertContains("RequirementsTest_a.js", $html); } public function testCommentedOutScriptTagIsIgnored() { $template = '<html><head></head><body><!--<script>alert("commented out");</script>-->' . '<h1>more content</h1></body></html>'; $backend = new TkiRequirements_Backend(); $backend->set_suffix_requirements(false); $src = $this->getCurrentRelativePath() . '/files/RequirementsTest_a.js'; $urlSrc = Controller::join_links(Director::baseURL(), $src); $backend->javascript($src); $html = $backend->includeInHTML(false, $template); $this->assertEquals('<html><head></head><body><!--<script>alert("commented out");</script>-->' . '<h1>more content</h1><script type="text/javascript" src="' . $urlSrc . '"></script></body></html>', $html); } public function testForceJsToBottom() { $backend = new TkiRequirements_Backend(); $backend->javascript('http://www.mydomain.com/test.js'); // Test matching with HTML5 <header> tags as well $template = '<html><head></head><body><header>My header</header><p>Body<script></script></p></body></html>'; // The expected outputs $JsInHead = "<html><head><script type=\"text/javascript\" src=\"http://www.mydomain.com/test.js\">" . "</script>\n</head><body><header>My header</header><p>Body<script></script></p></body></html>"; $JsInBody = "<html><head></head><body><header>My header</header><p>Body<script type=\"text/javascript\"" . " src=\"http://www.mydomain.com/test.js\"></script><script></script></p></body></html>"; $JsAtEnd = "<html><head></head><body><header>My header</header><p>Body<script></script></p><script " . "type=\"text/javascript\" src=\"http://www.mydomain.com/test.js\"></script></body></html>"; // Test if the script is before the head tag, not before the body. // Expected: $JsInHead $backend->set_write_js_to_body(false); $backend->set_force_js_to_bottom(false); $html = $backend->includeInHTML(false, $template); $this->assertNotEquals($JsInBody, $html); $this->assertNotEquals($JsAtEnd, $html); $this->assertEquals($JsInHead, $html); // Test if the script is before the first <script> tag, not before the body. // Expected: $JsInBody $backend->set_write_js_to_body(true); $backend->set_force_js_to_bottom(false); $html = $backend->includeInHTML(false, $template); $this->assertNotEquals($JsAtEnd, $html); $this->assertEquals($JsInBody, $html); // Test if the script is placed just before the closing bodytag, with write-to-body false. // Expected: $JsAtEnd $backend->set_write_js_to_body(false); $backend->set_force_js_to_bottom(true); $html = $backend->includeInHTML(false, $template); $this->assertNotEquals($JsInHead, $html); $this->assertNotEquals($JsInBody, $html); $this->assertEquals($JsAtEnd, $html); // Test if the script is placed just before the closing bodytag, with write-to-body true. // Expected: $JsAtEnd $backend->set_write_js_to_body(true); $backend->set_force_js_to_bottom(true); $html = $backend->includeInHTML(false, $template); $this->assertNotEquals($JsInHead, $html); $this->assertNotEquals($JsInBody, $html); $this->assertEquals($JsAtEnd, $html); } public function testSuffix() { $template = '<html><head></head><body><header>My header</header><p>Body</p></body></html>'; $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend; $backend->javascript($basePath .'/files/RequirementsTest_a.js'); $backend->javascript($basePath .'/files/RequirementsTest_b.js?foo=bar&bla=blubb'); $backend->css($basePath .'/files/RequirementsTest_a.css'); $backend->css($basePath .'/files/RequirementsTest_b.css?foo=bar&bla=blubb'); $backend->set_suffix_requirements(true); $html = $backend->includeInHTML(false, $template); $this->assertRegexp('/RequirementsTest_a\.js\?m=[\d]*"/', $html); $this->assertRegexp('/RequirementsTest_b\.js\?m=[\d]*&foo=bar&bla=blubb"/', $html); $this->assertRegexp('/RequirementsTest_a\.css\?m=[\d]*"/', $html); $this->assertRegexp('/RequirementsTest_b\.css\?m=[\d]*&foo=bar&bla=blubb"/', $html); $backend->set_suffix_requirements(false); $html = $backend->includeInHTML(false, $template); $this->assertNotContains('RequirementsTest_a.js=', $html); $this->assertNotRegexp('/RequirementsTest_a\.js\?m=[\d]*"/', $html); $this->assertNotRegexp('/RequirementsTest_b\.js\?m=[\d]*&foo=bar&bla=blubb"/', $html); $this->assertNotRegexp('/RequirementsTest_a\.css\?m=[\d]*"/', $html); $this->assertNotRegexp('/RequirementsTest_b\.css\?m=[\d]*&foo=bar&bla=blubb"/', $html); } /** * Ensure that if a JS snippet somewhere in the page (via requirements) contains </head> that it doesn't * get injected with requirements */ public function testHeadTagIsNotInjectedTwice() { $template = '<html><head></head><body><header>My header</header><p>Body</p></body></html>'; $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend; // The offending snippet that contains a closing head tag $backend->customScript('var myvar="<head></head>";'); // Insert a variety of random requirements $backend->css($basePath .'/files/RequirementsTest_a.css'); $backend->javascript($basePath .'/files/RequirementsTest_a.js'); $backend->insertHeadTags('<link rel="alternate" type="application/atom+xml" title="test" href="/" />'); // Case A: JS forced to bottom $backend->set_force_js_to_bottom(true); $this->assertContains('var myvar="<head></head>";', $backend->includeInHTML(false, $template)); // Case B: JS written to body $backend->set_force_js_to_bottom(false); $backend->set_write_js_to_body(true); $this->assertContains('var myvar="<head></head>";', $backend->includeInHTML(false, $template)); // Case C: Neither of the above $backend->set_write_js_to_body(false); $this->assertContains('var myvar="<head></head>";', $backend->includeInHTML(false, $template)); } public function assertFileIncluded($backend, $type, $files) { $type = strtolower($type); switch (strtolower($type)) { case 'css': $method = 'get_css'; $type = 'CSS'; break; case 'js': case 'javascript': case 'script': $method = 'get_javascript'; $type = 'JavaScript'; break; } $includedFiles = $backend->$method(); // Workaround for inconsistent return formats if($method == 'get_javascript') { $includedFiles = array_combine(array_values($includedFiles), array_values($includedFiles)); } if(is_array($files)) { $failedMatches = array(); foreach ($files as $file) { if(!array_key_exists($file, $includedFiles)) { $failedMatches[] = $file; } } $this->assertTrue( (count($failedMatches) == 0), "Failed asserting the $type files '" . implode("', '", $failedMatches) . "' have exact matches in the required elements:\n'" . implode("'\n'", array_keys($includedFiles)) . "'" ); } else { $this->assertTrue( (array_key_exists($files, $includedFiles)), "Failed asserting the $type file '$files' has an exact match in the required elements:\n'" . implode("'\n'", array_keys($includedFiles)) . "'" ); } } public function assertFileNotIncluded($backend, $type, $files) { $type = strtolower($type); switch ($type) { case 'css': $method = 'get_css'; $type = 'CSS'; break; case 'js': case 'get_javascript': case 'script': $method = 'get_javascript'; $type = 'JavaScript'; break; } $includedFiles = $backend->$method(); // Workaround for inconsistent return formats if($method == 'get_javascript') { $includedFiles = array_combine(array_values($includedFiles), array_values($includedFiles)); } if(is_array($files)) { $failedMatches = array(); foreach ($files as $file) { if(array_key_exists($file, $includedFiles)) { $failedMatches[] = $file; } } $this->assertTrue( (count($failedMatches) == 0), "Failed asserting the $type files '" . implode("', '", $failedMatches) . "' do not have exact matches in the required elements:\n'" . implode("'\n'", array_keys($includedFiles)) . "'" ); } else { $this->assertFalse( (array_key_exists($files, $includedFiles)), "Failed asserting the $type file '$files' does not have an exact match in the required elements:" . "\n'" . implode("'\n'", array_keys($includedFiles)) . "'" ); } } /* * ------------------------------------------------------------------------- * Same tests using new methods * ------------------------------------------------------------------------- */ public function testExternalUrlsUsinghNewMethods() { $backend = new TkiRequirements_Backend; $backend->set_combined_files_enabled(true); $backend->js('http://www.mydomain.com/test.js'); $backend->js('https://www.mysecuredomain.com/test.js'); $backend->js('//scheme-relative.example.com/test.js'); $backend->stylesheets('http://www.mydomain.com/test.css'); $backend->stylesheets('https://www.mysecuredomain.com/test.css'); $backend->stylesheets('//scheme-relative.example.com/test.css'); $html = $backend->includeInHTML(false, self::$html_template); $this->assertTrue( (strpos($html, 'http://www.mydomain.com/test.js') !== false), 'Load external javascript URL' ); $this->assertTrue( (strpos($html, 'https://www.mysecuredomain.com/test.js') !== false), 'Load external secure javascript URL' ); $this->assertTrue( (strpos($html, '//scheme-relative.example.com/test.js') !== false), 'Load external scheme-relative javascript URL' ); $this->assertTrue( (strpos($html, 'http://www.mydomain.com/test.css') !== false), 'Load external CSS URL' ); $this->assertTrue( (strpos($html, 'https://www.mysecuredomain.com/test.css') !== false), 'Load external secure CSS URL' ); $this->assertTrue( (strpos($html, '//scheme-relative.example.com/test.css') !== false), 'Load scheme-relative CSS URL' ); } protected function setupCombinedRequirementsUsingNewMethods($backend) { $basePath = $this->getCurrentRelativePath(); $backend->clear(); $backend->setCombinedFilesFolder('assets'); // clearing all previously generated requirements (just in case) $backend->clear_combined_files(); $backend->delete_combined_files('RequirementsTest_bc.js'); // require files normally (e.g. called from a FormField instance) $backend->js($basePath . '/files/RequirementsTest_a.js'); $backend->js($basePath . '/files/RequirementsTest_b.js'); $backend->js($basePath . '/files/RequirementsTest_c.js'); // require two of those files as combined includes $backend->extendedCombine( 'RequirementsTest_bc.js', array( $basePath . '/files/RequirementsTest_b.js', $basePath . '/files/RequirementsTest_c.js' ) ); } protected function setupCombinedNonrequiredRequirementsUsingNewMethods($backend) { $basePath = $this->getCurrentRelativePath(); $backend->clear(); $backend->setCombinedFilesFolder('assets'); // clearing all previously generated requirements (just in case) $backend->clear_combined_files(); $backend->delete_combined_files('RequirementsTest_bc.js'); // require files as combined includes $backend->extendedCombine( 'RequirementsTest_bc.js', array( $basePath . '/files/RequirementsTest_b.js', $basePath . '/files/RequirementsTest_c.js' ) ); } public function testCombinedJavascriptUsingNewMethods() { $backend = new TkiRequirements_Backend; $backend->set_combined_files_enabled(true); $backend->setCombinedFilesFolder('assets'); $this->setupCombinedRequirementsUsingNewMethods($backend); $combinedFilePath = Director::baseFolder() . '/assets/' . 'RequirementsTest_bc.js'; $html = $backend->includeInHTML(false, self::$html_template); /* COMBINED JAVASCRIPT FILE IS INCLUDED IN HTML HEADER */ $this->assertTrue((bool)preg_match('/src=".*\/RequirementsTest_bc\.js/', $html), 'combined javascript file is included in html header'); /* COMBINED JAVASCRIPT FILE EXISTS */ $this->assertTrue(file_exists($combinedFilePath), 'combined javascript file exists'); /* COMBINED JAVASCRIPT HAS CORRECT CONTENT */ $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false), 'combined javascript has correct content'); $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('c')") !== false), 'combined javascript has correct content'); /* COMBINED FILES ARE NOT INCLUDED TWICE */ $this->assertFalse((bool)preg_match('/src=".*\/RequirementsTest_b\.js/', $html), 'combined files are not included twice'); $this->assertFalse((bool)preg_match('/src=".*\/RequirementsTest_c\.js/', $html), 'combined files are not included twice'); /* NORMAL REQUIREMENTS ARE STILL INCLUDED */ $this->assertTrue((bool)preg_match('/src=".*\/RequirementsTest_a\.js/', $html), 'normal requirements are still included'); $backend->delete_combined_files('RequirementsTest_bc.js'); // Then do it again, this time not requiring the files beforehand $backend = new TkiRequirements_Backend; $backend->set_combined_files_enabled(true); $backend->setCombinedFilesFolder('assets'); $this->setupCombinedNonrequiredRequirementsUsingNewMethods($backend); $combinedFilePath = Director::baseFolder() . '/assets/' . 'RequirementsTest_bc.js'; $html = $backend->includeInHTML(false, self::$html_template); /* COMBINED JAVASCRIPT FILE IS INCLUDED IN HTML HEADER */ $this->assertTrue((bool)preg_match('/src=".*\/RequirementsTest_bc\.js/', $html), 'combined javascript file is included in html header'); /* COMBINED JAVASCRIPT FILE EXISTS */ $this->assertTrue(file_exists($combinedFilePath), 'combined javascript file exists'); /* COMBINED JAVASCRIPT HAS CORRECT CONTENT */ $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false), 'combined javascript has correct content'); $this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('c')") !== false), 'combined javascript has correct content'); /* COMBINED FILES ARE NOT INCLUDED TWICE */ $this->assertFalse((bool)preg_match('/src=".*\/RequirementsTest_b\.js/', $html), 'combined files are not included twice'); $this->assertFalse((bool)preg_match('/src=".*\/RequirementsTest_c\.js/', $html), 'combined files are not included twice'); $backend->delete_combined_files('RequirementsTest_bc.js'); } public function testCombinedCssUsingNewMethods() { $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend; $backend->set_combined_files_enabled(true); $backend->extendedCombine( 'print.css', array( $basePath . '/files/RequirementsTest_print_a.css', $basePath . '/files/RequirementsTest_print_b.css' ), array('media' => 'print') ); $html = $backend->includeInHTML(false, self::$html_template); $this->assertTrue((bool)preg_match('/href=".*\/print\.css/', $html), 'Print stylesheets have been combined.'); $this->assertTrue((bool)preg_match( '/media="print/', $html), 'Combined print stylesheet retains the media parameter' ); } public function testBlockedCombinedJavascriptUsingNewMethods() { $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend; $backend->set_combined_files_enabled(true); $backend->setCombinedFilesFolder('assets'); $combinedFilePath = Director::baseFolder() . '/assets/' . 'RequirementsTest_bc.js'; /* BLOCKED COMBINED FILES ARE NOT INCLUDED */ $this->setupCombinedRequirementsUsingNewMethods($backend); $backend->block('RequirementsTest_bc.js'); $backend->delete_combined_files('RequirementsTest_bc.js'); clearstatcache(); // needed to get accurate file_exists() results $html = $backend->includeInHTML(false, self::$html_template); $this->assertFalse((bool)preg_match('/src=".*\/RequirementsTest_bc\.js/', $html), 'blocked combined files are not included '); $backend->unblock('RequirementsTest_bc.js'); /* BLOCKED UNCOMBINED FILES ARE NOT INCLUDED */ $this->setupCombinedRequirementsUsingNewMethods($backend); $backend->block($basePath .'/files/RequirementsTest_b.js'); $backend->delete_combined_files('RequirementsTest_bc.js'); clearstatcache(); // needed to get accurate file_exists() results $html = $backend->includeInHTML(false, self::$html_template); $this->assertFalse((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false), 'blocked uncombined files are not included'); $backend->unblock('RequirementsTest_b.js'); /* A SINGLE FILE CAN'T BE INCLUDED IN TWO COMBINED FILES */ $this->setupCombinedRequirementsUsingNewMethods($backend); clearstatcache(); // needed to get accurate file_exists() results // This throws a notice-level error, so we prefix with @ @$backend->extendedCombine( 'RequirementsTest_ac.js', array( $basePath . '/files/RequirementsTest_a.js', $basePath . '/files/RequirementsTest_c.js' ) ); $combinedFiles = $backend->get_combine_files(); $this->assertEquals( array_keys($combinedFiles), array('RequirementsTest_bc.js'), "A single file can't be included in two combined files" ); $backend->delete_combined_files('RequirementsTest_bc.js'); } public function testArgsInUrlsUsinghNewMethods() { $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend; $backend->set_combined_files_enabled(true); $backend->js($basePath . '/files/RequirementsTest_a.js?test=1&test=2&test=3'); $backend->stylesheets($basePath . '/files/RequirementsTest_a.css?test=1&test=2&test=3'); $backend->delete_combined_files('RequirementsTest_bc.js'); $html = $backend->includeInHTML(false, self::$html_template); /* Javascript has correct path */ $this->assertTrue( (bool)preg_match('/src=".*\/RequirementsTest_a\.js\?m=\d\d+&test=1&test=2&test=3/',$html), 'javascript has correct path'); /* CSS has correct path */ $this->assertTrue( (bool)preg_match('/href=".*\/RequirementsTest_a\.css\?m=\d\d+&test=1&test=2&test=3/',$html), 'css has correct path'); } public function testRequirementsBackendUsinghNewMethods() { $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend(); $backend->js($basePath . '/a.js'); $this->assertTrue(count($backend->get_javascript()) == 1, "There should be only 1 file included in required javascript."); $this->assertTrue(in_array($basePath . '/a.js', $backend->get_javascript()), "a.js should be included in required javascript."); $backend->js($basePath . '/b.js'); $this->assertTrue(count($backend->get_javascript()) == 2, "There should be 2 files included in required javascript."); $backend->block($basePath . '/a.js'); $this->assertTrue(count($backend->get_javascript()) == 1, "There should be only 1 file included in required javascript."); $this->assertFalse(in_array($basePath . '/a.js', $backend->get_javascript()), "a.js should not be included in required javascript after it has been blocked."); $this->assertTrue(in_array($basePath . '/b.js', $backend->get_javascript()), "b.js should be included in required javascript."); $backend->stylesheets($basePath . '/a.css'); $this->assertTrue(count($backend->get_css()) == 1, "There should be only 1 file included in required css."); $this->assertArrayHasKey($basePath . '/a.css', $backend->get_css(), "a.css should be in required css."); $backend->block($basePath . '/a.css'); $this->assertTrue(count($backend->get_css()) == 0, "There should be nothing in required css after file has been blocked."); } public function testJsWriteToBodyUsinghNewMethods() { $backend = new TkiRequirements_Backend(); $backend->js('http://www.mydomain.com/test.js'); // Test matching with HTML5 <header> tags as well $template = '<html><head></head><body><header>My header</header><p>Body</p></body></html>'; $backend->set_write_js_to_body(false); $html = $backend->includeInHTML(false, $template); $this->assertContains('<head><script', $html); $backend->set_write_js_to_body(true); $html = $backend->includeInHTML(false, $template); $this->assertNotContains('<head><script', $html); $this->assertContains('</script></body>', $html); } public function testIncludedJsIsNotCommentedOutUsinghNewMethods() { $template = '<html><head></head><body><!--<script>alert("commented out");</script>--></body></html>'; $backend = new TkiRequirements_Backend(); $backend->js($this->getCurrentRelativePath() . '/files/RequirementsTest_a.js'); $html = $backend->includeInHTML(false, $template); //wiping out commented-out html $html = preg_replace('/<!--(.*)-->/Uis', '', $html); $this->assertContains("RequirementsTest_a.js", $html); } public function testCommentedOutScriptTagIsIgnoredUsinghNewMethods() { $template = '<html><head></head><body><!--<script>alert("commented out");</script>-->' . '<h1>more content</h1></body></html>'; $backend = new TkiRequirements_Backend(); $backend->set_suffix_requirements(false); $src = $this->getCurrentRelativePath() . '/files/RequirementsTest_a.js'; $urlSrc = Controller::join_links(Director::baseURL(), $src); $backend->js($src); $html = $backend->includeInHTML(false, $template); $this->assertEquals('<html><head></head><body><!--<script>alert("commented out");</script>-->' . '<h1>more content</h1><script type="text/javascript" src="' . $urlSrc . '"></script></body></html>', $html); } public function testForceJsToBottomUsingNewMethods() { $backend = new TkiRequirements_Backend(); $backend->js('http://www.mydomain.com/test.js'); // Test matching with HTML5 <header> tags as well $template = '<html><head></head><body><header>My header</header><p>Body<script></script></p></body></html>'; // The expected outputs $JsInHead = "<html><head><script type=\"text/javascript\" src=\"http://www.mydomain.com/test.js\">" . "</script>\n</head><body><header>My header</header><p>Body<script></script></p></body></html>"; $JsInBody = "<html><head></head><body><header>My header</header><p>Body<script type=\"text/javascript\"" . " src=\"http://www.mydomain.com/test.js\"></script><script></script></p></body></html>"; $JsAtEnd = "<html><head></head><body><header>My header</header><p>Body<script></script></p><script " . "type=\"text/javascript\" src=\"http://www.mydomain.com/test.js\"></script></body></html>"; // Test if the script is before the head tag, not before the body. // Expected: $JsInHead $backend->set_write_js_to_body(false); $backend->set_force_js_to_bottom(false); $html = $backend->includeInHTML(false, $template); $this->assertNotEquals($JsInBody, $html); $this->assertNotEquals($JsAtEnd, $html); $this->assertEquals($JsInHead, $html); // Test if the script is before the first <script> tag, not before the body. // Expected: $JsInBody $backend->set_write_js_to_body(true); $backend->set_force_js_to_bottom(false); $html = $backend->includeInHTML(false, $template); $this->assertNotEquals($JsAtEnd, $html); $this->assertEquals($JsInBody, $html); // Test if the script is placed just before the closing bodytag, with write-to-body false. // Expected: $JsAtEnd $backend->set_write_js_to_body(false); $backend->set_force_js_to_bottom(true); $html = $backend->includeInHTML(false, $template); $this->assertNotEquals($JsInHead, $html); $this->assertNotEquals($JsInBody, $html); $this->assertEquals($JsAtEnd, $html); // Test if the script is placed just before the closing bodytag, with write-to-body true. // Expected: $JsAtEnd $backend->set_write_js_to_body(true); $backend->set_force_js_to_bottom(true); $html = $backend->includeInHTML(false, $template); $this->assertNotEquals($JsInHead, $html); $this->assertNotEquals($JsInBody, $html); $this->assertEquals($JsAtEnd, $html); } public function testSuffixUsinghNewMethods() { $template = '<html><head></head><body><header>My header</header><p>Body</p></body></html>'; $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend; $backend->js($basePath .'/files/RequirementsTest_a.js'); $backend->js($basePath .'/files/RequirementsTest_b.js?foo=bar&bla=blubb'); $backend->stylesheets($basePath .'/files/RequirementsTest_a.css'); $backend->stylesheets($basePath .'/files/RequirementsTest_b.css?foo=bar&bla=blubb'); $backend->set_suffix_requirements(true); $html = $backend->includeInHTML(false, $template); $this->assertRegexp('/RequirementsTest_a\.js\?m=[\d]*"/', $html); $this->assertRegexp('/RequirementsTest_b\.js\?m=[\d]*&foo=bar&bla=blubb"/', $html); $this->assertRegexp('/RequirementsTest_a\.css\?m=[\d]*"/', $html); $this->assertRegexp('/RequirementsTest_b\.css\?m=[\d]*&foo=bar&bla=blubb"/', $html); $backend->set_suffix_requirements(false); $html = $backend->includeInHTML(false, $template); $this->assertNotContains('RequirementsTest_a.js=', $html); $this->assertNotRegexp('/RequirementsTest_a\.js\?m=[\d]*"/', $html); $this->assertNotRegexp('/RequirementsTest_b\.js\?m=[\d]*&foo=bar&bla=blubb"/', $html); $this->assertNotRegexp('/RequirementsTest_a\.css\?m=[\d]*"/', $html); $this->assertNotRegexp('/RequirementsTest_b\.css\?m=[\d]*&foo=bar&bla=blubb"/', $html); } /** * Ensure that if a JS snippet somewhere in the page (via requirements) contains </head> that it doesn't * get injected with requirements */ public function testHeadTagIsNotInjectedTwiceUsinghNewMethods() { $template = '<html><head></head><body><header>My header</header><p>Body</p></body></html>'; $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend; // The offending snippet that contains a closing head tag $backend->customScript('var myvar="<head></head>";'); // Insert a variety of random requirements $backend->stylesheets($basePath .'/files/RequirementsTest_a.css'); $backend->js($basePath .'/files/RequirementsTest_a.js'); $backend->insertHeadTags('<link rel="alternate" type="application/atom+xml" title="test" href="/" />'); // Case A: JS forced to bottom $backend->set_force_js_to_bottom(true); $this->assertContains('var myvar="<head></head>";', $backend->includeInHTML(false, $template)); // Case B: JS written to body $backend->set_force_js_to_bottom(false); $backend->set_write_js_to_body(true); $this->assertContains('var myvar="<head></head>";', $backend->includeInHTML(false, $template)); // Case C: Neither of the above $backend->set_write_js_to_body(false); $this->assertContains('var myvar="<head></head>";', $backend->includeInHTML(false, $template)); } /* * ------------------------------------------------------------------------- * Tests for new metnods * ------------------------------------------------------------------------- */ protected static function access_method($name) { $class = new ReflectionClass('TkiRequirements_Backend'); $method = $class->getMethod($name); $method->setAccessible(true); return $method; } public function testGetFileInfo() { $backend = new TkiRequirements_Backend; $getFileInfoMethod = self::access_method('getFileInfo'); /* * 'css' type */ // Test string $file = 'file1.css'; $result = $getFileInfoMethod->invokeArgs($backend,array($file)); $this->assertTrue((is_array($result) && count($result) === 2),'File info is an array with two items'); $this->assertEquals('file1.css',$result['path'],'File path value contains file name'); $this->assertEquals('css',$result['ext'],'File ext value contains correct extension'); // Test associative array $file = array('path' => 'file2.css', 'ext' => 'css'); $result = $getFileInfoMethod->invokeArgs($backend,array($file)); $this->assertTrue((is_array($result) && count($result) === 2),'File info is an array with two items'); $this->assertEquals('file2.css',$result['path'],'File path value contains file name'); $this->assertEquals('css',$result['ext'],'File ext value contains correct extension'); // Test numeric array $file = array('file3.css','css'); $result = $getFileInfoMethod->invokeArgs($backend,array($file)); $this->assertTrue((is_array($result) && count($result) === 2),'File info is an array with two items'); $this->assertEquals('file3.css',$result['path'],'File path value contains file name'); $this->assertEquals('css',$result['ext'],'File ext value contains correct extension'); // Test array with path only $file = array('file4.css'); $result = $getFileInfoMethod->invokeArgs($backend,array($file)); $this->assertTrue((is_array($result) && count($result) === 2),'File info is an array with two items'); $this->assertEquals('file4.css',$result['path'],'File path value contains file name'); $this->assertEquals('css',$result['ext'],'File ext value contains correct extension'); /* * 'js' type */ // Test string $file = 'file1.js'; $result = $getFileInfoMethod->invokeArgs($backend,array($file)); $this->assertTrue((is_array($result) && count($result) === 2),'File info is an array with two items'); $this->assertEquals('file1.js',$result['path'],'File path value contains file name'); $this->assertEquals('js',$result['ext'],'File ext value contains correct extension'); // Test associative array $file = array('path' => 'file2.js', 'ext' => 'js'); $result = $getFileInfoMethod->invokeArgs($backend,array($file)); $this->assertTrue((is_array($result) && count($result) === 2),'File info is an array with two items'); $this->assertEquals('file2.js',$result['path'],'File path value contains file name'); $this->assertEquals('js',$result['ext'],'File ext value contains correct extension'); // Test numeric array $file = array('file3.js','js'); $result = $getFileInfoMethod->invokeArgs($backend,array($file)); $this->assertTrue((is_array($result) && count($result) === 2),'File info is an array with two items'); $this->assertEquals('file3.js',$result['path'],'File path value contains file name'); $this->assertEquals('js',$result['ext'],'File ext value contains correct extension'); // Test array with path only $file = array('file4.js'); $result = $getFileInfoMethod->invokeArgs($backend,array($file)); $this->assertTrue((is_array($result) && count($result) === 2),'File info is an array with two items'); $this->assertEquals('file4.js',$result['path'],'File path value contains file name'); $this->assertEquals('js',$result['ext'],'File ext value contains correct extension'); /* * 'javascript' type */ // Test associative array $file = array('path' => 'file1.js', 'ext' => 'javascript'); $result = $getFileInfoMethod->invokeArgs($backend,array($file)); $this->assertTrue((is_array($result) && count($result) === 2),'File info is an array with two items'); $this->assertEquals('file1.js',$result['path'],'File path value contains file name'); $this->assertEquals('js',$result['ext'],'File ext value contains correct extension'); // Test numeric array $file = array('file2.js','javascript'); $result = $getFileInfoMethod->invokeArgs($backend,array($file)); $this->assertTrue((is_array($result) && count($result) === 2),'File info is an array with two items'); $this->assertEquals('file2.js',$result['path'],'File path value contains file name'); $this->assertEquals('js',$result['ext'],'File ext value contains correct extension'); } public function testSeparateFilesByType() { $backend = new TkiRequirements_Backend; $basePath = $this->getCurrentRelativePath(); $separateFilesByTypeMethod = self::access_method('separateFilesByType'); /* * Non-combined requirements */ $files = $this->setupMultipleNonCombinedRequirements(); $separated = $separateFilesByTypeMethod->invokeArgs($backend,array($files)); // Test CSS files were separated $this->assertArrayHasKey('css',$separated, 'Separated files array has "css" key'); $arrayDiff = array_diff(array( $basePath . '/files/RequirementsTest_a.css', $basePath . '/files/RequirementsTest_b.css', $basePath . '/files/RequirementsTest_c.css' ),$separated['css']); $this->assertTrue(empty($arrayDiff),'Separated array has all required CSS files'); // Test JavaScript files were separated $this->assertArrayHasKey('js',$separated, 'Separated files array has "js" key'); $arrayDiff = array_diff(array( $basePath . '/files/RequirementsTest_a.js', $basePath . '/files/RequirementsTest_b.js', $basePath . '/files/RequirementsTest_c.js' ),$separated['js']); $this->assertTrue(empty($arrayDiff),'Separated array has all required JS files'); } public function testRequireFiles() { $backend = new TkiRequirements_Backend; $basePath = $this->getCurrentRelativePath(); $backend->setCombinedFilesFolder('assets'); /* * Non-combined */ // Test different formats allowed for $files argument $backend->requireFiles($this->setupMultipleNonCombinedRequirements()); $html = $backend->includeInHTML(false, self::$html_template); $this->assertContains("RequirementsTest_a.css", $html, 'Stylesheet A included'); $this->assertContains("RequirementsTest_b.css", $html, 'Stylesheet B included'); $this->assertContains("RequirementsTest_c.css", $html, 'Stylesheet C included'); $this->assertContains("RequirementsTest_a.js", $html, 'Script A included'); $this->assertContains("RequirementsTest_b.js", $html, 'Script B included'); $this->assertContains("RequirementsTest_c.js", $html, 'Script C included'); $backend->clear(); /* * Combined */ // Test different formats allowed for $files argument $backend->requireFiles($this->setupMultipleCombinedRequirements()); $html = $backend->includeInHTML(false, self::$html_template); $this->assertContains("combined_css_a.css", $html, 'Combined CSS a included'); $this->assertNotContains("RequirementsTest_a.css", $html, 'Stylesheet A not linked'); $this->assertContains("combined_css_bc.css", $html, 'Combined CSS bc included'); $this->assertNotContains("RequirementsTest_b.css", $html, 'Stylesheet B not linked'); $this->assertNotContains("RequirementsTest_c.css", $html, 'Stylesheet C not linked'); $this->assertContains("combined_css_de.css", $html, 'Combined CSS de included'); $this->assertNotContains("RequirementsTest_d.css", $html, 'Stylesheet D not linked'); $this->assertNotContains("RequirementsTest_e.css", $html, 'Stylesheet E not linked'); $this->assertContains("combined_js_ab.js", $html, 'Combined JS ab included'); $this->assertNotContains("RequirementsTest_a.js", $html, 'Script A not linked'); $this->assertNotContains("RequirementsTest_b.js", $html, 'Script B not linked'); $this->assertContains("combined_js_cd.js", $html, 'Combined JS cd included'); $this->assertNotContains("RequirementsTest_c.js", $html, 'Script C not linked'); $this->assertNotContains("RequirementsTest_d.js", $html, 'Script D not linked'); $this->assertContains("combined_js_e.js", $html, 'Combined JS e included'); $this->assertNotContains("RequirementsTest_e.js", $html, 'Script E not linked'); $this->assertContains("combined_mixed_f.css", $html, 'Combined CSS f included'); $this->assertContains("combined_mixed_f.js", $html, 'Combined JS f included'); $this->assertNotContains("RequirementsTest_f.css", $html, 'Stylesheet F not linked'); $this->assertNotContains("RequirementsTest_f.js", $html, 'Script F not linked'); $backend->clear(); $backend->clear_combined_files(); $backend->delete_combined_files('combined_css_a.css'); $backend->delete_combined_files('combined_css_bc.css'); $backend->delete_combined_files('combined_css_de.css'); $backend->delete_combined_files('combined_js_ab.js'); $backend->delete_combined_files('combined_js_cd.js'); $backend->delete_combined_files('combined_js_e.js'); $backend->delete_combined_files('combined_mixed_f.css'); $backend->delete_combined_files('combined_mixed_f.js'); } protected function setupMultipleCombinedRequirements() { $basePath = $this->getCurrentRelativePath(); return array( // Combine key and string value 'combined_css_a' => $basePath . '/files/RequirementsTest_a.css', // Combine key and array of simple path values 'combined_css_bc' => array( $basePath . '/files/RequirementsTest_b.css', $basePath . '/files/RequirementsTest_c.css' ), // Associative array with path value 'combined_css_de' => array( array('path' => $basePath . '/files/RequirementsTest_d.css'), array('path' => $basePath . '/files/RequirementsTest_e.css') ), // Combine key and nested numeric array with path value 'combined_js_ab' => array( array($basePath . '/files/RequirementsTest_a.js'), array($basePath . '/files/RequirementsTest_b.js') ), // Combine key and nested numeric array with path and type values 'combined_js_cd' => array( array($basePath . '/files/RequirementsTest_c.js', 'js'), array($basePath . '/files/RequirementsTest_d.js', 'js') ), // As above, with javascript key 'combined_js_e' => array(array($basePath . '/files/RequirementsTest_e.js', 'javascript')), // Mixed 'combined_mixed_f' => array( $basePath . '/files/RequirementsTest_f.css', $basePath . '/files/RequirementsTest_f.js' ) ); } protected function setupMultipleNonCombinedRequirements() { $basePath = $this->getCurrentRelativePath(); return array( // String path $basePath . '/files/RequirementsTest_a.css', // Numeric array with path value array($basePath . '/files/RequirementsTest_b.css'), // Associative array with path value array('path' => $basePath . '/files/RequirementsTest_c.css'), // Numeric array with path and type values array($basePath . '/files/RequirementsTest_a.js','js'), // Associative array with path and type keys and values array('path' => $basePath . '/files/RequirementsTest_b.js','type' => 'js'), // As above, with javascript type array('path' => $basePath . '/files/RequirementsTest_c.js','type' => 'javascript') ); } /* * ------------------------------------------------------------------------- * Tests for new features * ------------------------------------------------------------------------- */ public function testCSSPrioritisation() { $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend; Config::inst()->update('TkiRequirements_Backend','default_priority',50); // Set default /* * Uncombined */ /* Without prioritisation */ $backend->set_combined_files_enabled(false); // Single requirement $backend->stylesheets($basePath . '/files/RequirementsTest_a.css'); // Multiple requirement $backend->stylesheets(array( $basePath . '/files/RequirementsTest_b.css', $basePath . '/files/RequirementsTest_c.css') ); $html = $backend->includeInHTML(false, self::$html_template); $posA = strpos($html,'RequirementsTest_a.css'); $posB = strpos($html,'RequirementsTest_b.css'); $posC = strpos($html,'RequirementsTest_c.css'); $this->assertTrue(($posA !== false), 'Stylesheet A included'); $this->assertTrue(($posB !== false), 'Stylesheet B included'); $this->assertTrue(($posC !== false), 'Stylesheet C included'); $this->assertTrue((($posA < $posB) && ($posB < $posC)), 'Unprioritised stylesheets loaded in order required' ); /* With prioritisation */ $backend->clear(); // Single requirement $backend->stylesheets($basePath . '/files/RequirementsTest_a.css',null,20); $backend->stylesheets($basePath . '/files/RequirementsTest_b.css'); // Default priority (50) // // Multiple requirements $backend->stylesheets(array( $basePath . '/files/RequirementsTest_c.css', $basePath . '/files/RequirementsTest_d.css' ),null,70); $html = $backend->includeInHTML(false, self::$html_template); $posA = strpos($html,'RequirementsTest_a.css'); $posB = strpos($html,'RequirementsTest_b.css'); $posC = strpos($html,'RequirementsTest_c.css'); $posD = strpos($html,'RequirementsTest_d.css'); $this->assertTrue(($posA !== false), 'Stylesheet A included'); $this->assertTrue(($posB !== false), 'Stylesheet B included'); $this->assertTrue(($posC !== false), 'Stylesheet C included'); $this->assertTrue(($posD !== false), 'Stylesheet D included'); // Order should be: c, d, b, a $this->assertTrue((($posC < $posD) && ($posD < $posB) && ($posB < $posA)), 'Prioritised stylesheets loaded in order specified' ); $backend->clear(); /* * Combined */ $backend->set_combined_files_enabled(true); /* Without prioritisation */ // Single requirement $backend->stylesheets($basePath . '/files/RequirementsTest_a.css'); $backend->stylesheets($basePath . '/files/RequirementsTest_b.css'); // Multiple requirements $backend->stylesheets(array( 'RequirementsTest_cd' => array( $basePath . '/files/RequirementsTest_c.css', $basePath . '/files/RequirementsTest_d.css' ) )); $html = $backend->includeInHTML(false, self::$html_template); $posA = strpos($html,'RequirementsTest_a.css'); $posB = strpos($html,'RequirementsTest_b.css'); $posCD = strpos($html,'RequirementsTest_cd.css'); $this->assertTrue(($posA !== false), 'Stylesheet A linked'); $this->assertTrue(($posB !== false), 'Stylesheet B linked'); $this->assertNotContains('RequirementsTest_c.css',$html,'Stylesheet C not linked'); $this->assertNotContains('RequirementsTest_d.css',$html,'Stylesheet D not linked'); $this->assertTrue(($posCD !== false), 'Combined stylesheet CD linked'); // Order should be: a, b, cd $this->assertTrue((($posA < $posB) && ($posB < $posCD)), 'Unprioritised combined stylesheets loaded in order required' ); $backend->clear(); $backend->clear_combined_files(); $backend->delete_combined_files('RequirementsTest_cd.css'); /* With prioritisation */ // Single requirement $backend->stylesheets($basePath . '/files/RequirementsTest_a.css',null,30); $backend->stylesheets($basePath . '/files/RequirementsTest_b.css'); // Default priority // // Multiple requirements $backend->stylesheets(array( 'RequirementsTest_cd' => array( $basePath . '/files/RequirementsTest_c.css', $basePath . '/files/RequirementsTest_d.css' ) ),null,70); // Single requirement $html = $backend->includeInHTML(false, self::$html_template); $posA = strpos($html,'RequirementsTest_a.css'); $posB = strpos($html,'RequirementsTest_b.css'); $posCD = strpos($html,'RequirementsTest_cd.css'); $this->assertTrue(($posA !== false), 'Stylesheet A linked'); $this->assertTrue(($posB !== false), 'Stylesheet B linked'); $this->assertNotContains('RequirementsTest_c.css',$html,'Stylesheet C not linked'); $this->assertNotContains('RequirementsTest_d.css',$html,'Stylesheet D not linked'); $this->assertTrue(($posCD !== false), 'Combined stylesheet CD linked'); // Order should be: cd, b, a $this->assertTrue((($posCD < $posB) && ($posB < $posA)), 'Prioritised combined stylesheets loaded in order specified' ); $backend->clear(); $backend->clear_combined_files(); $backend->delete_combined_files('RequirementsTest_cd.css'); } public function testJSPrioritisation() { $basePath = $this->getCurrentRelativePath(); $backend = new TkiRequirements_Backend; Config::inst()->update('TkiRequirements_Backend','default_priority',50); // Set default /* * Uncombined */ /* Without prioritisation */ $backend->set_combined_files_enabled(false); // Single requirement $backend->js($basePath . '/files/RequirementsTest_a.js'); // Multiple requirement $backend->js(array( $basePath . '/files/RequirementsTest_b.js', $basePath . '/files/RequirementsTest_c.js') ); $html = $backend->includeInHTML(false, self::$html_template); $posA = strpos($html,'RequirementsTest_a.js'); $posB = strpos($html,'RequirementsTest_b.js'); $posC = strpos($html,'RequirementsTest_c.js'); $this->assertTrue(($posA !== false), 'Script A included'); $this->assertTrue(($posB !== false), 'Script B included'); $this->assertTrue(($posC !== false), 'Script C included'); $this->assertTrue((($posA < $posB) && ($posB < $posC)), 'Unprioritised scripts loaded in order required' ); /* With prioritisation */ $backend->clear(); // Single requirement $backend->js($basePath . '/files/RequirementsTest_a.js',null,30); $backend->js($basePath . '/files/RequirementsTest_b.js'); // Default priority (50) // // Multiple requirements $backend->js(array( $basePath . '/files/RequirementsTest_c.js', $basePath . '/files/RequirementsTest_d.js' ),null,70); $html = $backend->includeInHTML(false, self::$html_template); $posA = strpos($html,'RequirementsTest_a.js'); $posB = strpos($html,'RequirementsTest_b.js'); $posC = strpos($html,'RequirementsTest_c.js'); $posD = strpos($html,'RequirementsTest_d.js'); $this->assertTrue(($posA !== false), 'Script A included'); $this->assertTrue(($posB !== false), 'Script B included'); $this->assertTrue(($posC !== false), 'Script C included'); $this->assertTrue(($posD !== false), 'Script D included'); // Order should be: c, d, b, a $this->assertTrue((($posC < $posD) && ($posD < $posB) && ($posB < $posA)), 'Prioritised scripts loaded in order specified' ); $backend->clear(); /* * Combined */ $backend->set_combined_files_enabled(true); /* Without prioritisation */ // Single requirement $backend->js($basePath . '/files/RequirementsTest_a.js'); $backend->js($basePath . '/files/RequirementsTest_b.js'); // Multiple requirements $backend->js(array( 'RequirementsTest_cd' => array( $basePath . '/files/RequirementsTest_c.js', $basePath . '/files/RequirementsTest_d.js' ) )); $html = $backend->includeInHTML(false, self::$html_template); $posA = strpos($html,'RequirementsTest_a.js'); $posB = strpos($html,'RequirementsTest_b.js'); $posCD = strpos($html,'RequirementsTest_cd.js'); $this->assertTrue(($posA !== false), 'Script A linked'); $this->assertTrue(($posB !== false), 'Script B linked'); $this->assertNotContains('RequirementsTest_c.js',$html,'Script C not linked'); $this->assertNotContains('RequirementsTest_d.js',$html,'Script D not linked'); $this->assertTrue(($posCD !== false), 'Combined script CD linked'); // Order should be: a, b, cd $this->assertTrue((($posA < $posB) && ($posB < $posCD)), 'Unprioritised combined scripts loaded in order required' ); $backend->clear(); $backend->clear_combined_files(); $backend->delete_combined_files('RequirementsTest_cd.js'); /* With prioritisation */ // Single requirement $backend->js($basePath . '/files/RequirementsTest_a.js',null,30); $backend->js($basePath . '/files/RequirementsTest_b.js'); // Default priority // // Multiple requirements $backend->js(array( 'RequirementsTest_cd' => array( $basePath . '/files/RequirementsTest_c.js', $basePath . '/files/RequirementsTest_d.js' ) ),null,70); // Single requirement $html = $backend->includeInHTML(false, self::$html_template); $posA = strpos($html,'RequirementsTest_a.js'); $posB = strpos($html,'RequirementsTest_b.js'); $posCD = strpos($html,'RequirementsTest_cd.js'); $this->assertTrue(($posA !== false), 'Script A linked'); $this->assertTrue(($posB !== false), 'Script B linked'); $this->assertNotContains('RequirementsTest_c.js',$html,'Script C not linked'); $this->assertNotContains('RequirementsTest_d.js',$html,'Script D not linked'); $this->assertTrue(($posCD !== false), 'Combined script CD linked'); // Order should be: cd, b, a $this->assertTrue((($posCD < $posB) && ($posB < $posA)), 'Prioritised combined scripts loaded in order specified' ); $backend->clear(); $backend->clear_combined_files(); $backend->delete_combined_files('RequirementsTest_cd.js'); } protected function setupRequirementsForJsLocation($backend) { $backend->clear(); // Require JS without location and priority (use defaults) $backend->js('http://www.mydomain.com/test_c.js'); // Require JS with location and without priority // Default priority (50) $backend->js('http://www.mydomain.com/test_d.js', 'bottom'); // Require JS with location and priority $backend->js('http://www.mydomain.com/test_b.js','body', 60); // Require JS with location and priority $backend->js('http://www.mydomain.com/test_a.js', 'head', 70); } public function testSpecifyingJsLocation() { $backend = new TkiRequirements_Backend(); /* * Setup */ // Test matching with HTML5 <header> tags as well $template = '<html><head></head><body><header>My header</header><p>Body<script></script></p></body></html>'; $jsInHead = "<html><head>" . "<script type=\"text/javascript\" src=\"http://www.mydomain.com/test_a.js\"></script>\n" . "<script type=\"text/javascript\" src=\"http://www.mydomain.com/test_b.js\"></script>\n" . "<script type=\"text/javascript\" src=\"http://www.mydomain.com/test_c.js\"></script>\n" . "<script type=\"text/javascript\" src=\"http://www.mydomain.com/test_d.js\"></script>\n" . "</head><body><header>My header</header><p>Body<script></script></p></body></html>"; $jsInAllLocations = "<html><head>" . "<script type=\"text/javascript\" src=\"http://www.mydomain.com/test_a.js\"></script>\n" . "</head><body><header>My header</header><p>Body" . "<script type=\"text/javascript\" src=\"http://www.mydomain.com/test_b.js\"></script>" . "<script type=\"text/javascript\" src=\"http://www.mydomain.com/test_c.js\"></script>" . "<script></script></p>" . "<script type=\"text/javascript\" src=\"http://www.mydomain.com/test_d.js\"></script>" . "</body></html>"; $jsAtBottom = "<html><head></head><body><header>My header</header><p>Body<script></script></p>" . "<script type=\"text/javascript\" src=\"http://www.mydomain.com/test_a.js\"></script>" . "<script type=\"text/javascript\" src=\"http://www.mydomain.com/test_b.js\"></script>" . "<script type=\"text/javascript\" src=\"http://www.mydomain.com/test_c.js\"></script>" . "<script type=\"text/javascript\" src=\"http://www.mydomain.com/test_d.js\"></script>" . "</body></html>"; $this->setupRequirementsForJsLocation($backend); /* * Test JS forced into head * Expected: $jsInHead */ // Test all scripts moved into head before the closing head tag, and maintain // prioritisation. $backend->set_write_js_to_body(false); $backend->set_force_js_to_bottom(false); $html = $backend->includeInHTML(false, $template); $this->assertNotEquals($jsInAllLocations, $html); $this->assertNotEquals($jsAtBottom, $html); $this->assertEquals($jsInHead, $html); /* * Test JS in all locations * Expected: $jsInAllLocations */ // Test one script in head before the closing head tag, // and two scripts in body before first <script> tag, // and one script at the bottom. $backend->set_write_js_to_body(true); $backend->set_force_js_to_bottom(false); $html = $backend->includeInHTML(false, $template); $this->assertNotEquals($jsInHead, $html); $this->assertNotEquals($jsAtBottom, $html); $this->assertEquals($jsInAllLocations, $html); /* * Test JS forced to end of body * Expected: $jsAtBottom */ // Test all scripts placed just before the closing body tag, and maintain // prioritisation. (write_js_to_body = false) $backend->set_write_js_to_body(false); $backend->set_force_js_to_bottom(true); $html = $backend->includeInHTML(false, $template); $this->assertNotEquals($jsInHead, $html); $this->assertNotEquals($jsInAllLocations, $html); $this->assertEquals($jsAtBottom, $html); // Test all scripts placed just before the closing body tag, and maintain // prioritisation. (write_js_to_body = true) $backend->set_write_js_to_body(true); $backend->set_force_js_to_bottom(true); $html = $backend->includeInHTML(false, $template); $this->assertNotEquals($jsInHead, $html); $this->assertNotEquals($jsInAllLocations, $html); $this->assertEquals($jsAtBottom, $html); } protected function setupMixedRequirements($backend) { $basePath = $this->getCurrentRelativePath(); /* * CSS */ // Combined css $backend->stylesheets(array( 'RequirementsTest_de' => array( $basePath . '/files/RequirementsTest_d.css', $basePath . '/files/RequirementsTest_e.css' ), ),null,30); // Associative array with path value - Default priority $backend->stylesheets(array( array('path' => $basePath . '/files/RequirementsTest_c.css') )); // // Numeric array with path and type values $backend->stylesheets(array( array($basePath . '/files/RequirementsTest_b.css') ),null,70); /* * JS */ // Associative array with path value $backend->js(array( array('path' => $basePath . '/files/RequirementsTest_e.js') ),null,30); // Combined js - Default priority $backend->js(array( 'RequirementsTest_cd' => array( $basePath . '/files/RequirementsTest_c.js', $basePath . '/files/RequirementsTest_d.js' ) )); // Numeric array with path and type values $backend->js(array( array($basePath . '/files/RequirementsTest_b.js') ),'head',70); /* * Mixed */ // String path $backend->requireFiles(array( $basePath . '/files/RequirementsTest_a.css', $basePath . '/files/RequirementsTest_a.js' ),array('priority' => 70)); /* * Output order should be the following... * CSS: a, b, c, de * JS: a, b, cd, e */ } } |