Civi::url() - Add test-coverage
authorTim Otten <totten@civicrm.org>
Mon, 24 Jul 2023 06:56:47 +0000 (23:56 -0700)
committerTim Otten <totten@civicrm.org>
Mon, 24 Jul 2023 22:41:06 +0000 (15:41 -0700)
tests/phpunit/Civi/Core/UrlTest.php [new file with mode: 0644]
tests/phpunit/E2E/Core/PathUrlTest.php

diff --git a/tests/phpunit/Civi/Core/UrlTest.php b/tests/phpunit/Civi/Core/UrlTest.php
new file mode 100644 (file)
index 0000000..35c261f
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+
+namespace Civi\Core;
+
+use Civi;
+
+/**
+ * Test generation of URLs via `Civi::url()` (`Civi\Core\Url`).
+ *
+ * This class is focused on portable aspects of the functionality.
+ * There is also some coverage of the UF-specific parts in the E2E suite.
+ *
+ * @see \E2E\Core\PathUrlTest
+ * @group headless
+ */
+class UrlTest extends \CiviUnitTestCase {
+
+  public function setUp(): void {
+    $parts = explode('/', CIVICRM_UF_BASEURL);
+    $this->assertRegexp(';^[a-z0-9\.\-]+(:\d+)?$;', $parts[2], 'CIVICRM_UF_BASEURL should have domain name and/or port');
+    $tmpVars['_SERVER']['HTTP_HOST'] = $parts[2];
+    \CRM_Utils_GlobalStack::singleton()->push($tmpVars);
+
+    parent::setUp();
+    $this->useTransaction();
+  }
+
+  protected function tearDown(): void {
+    parent::tearDown();
+    \CRM_Utils_GlobalStack::singleton()->pop();
+  }
+
+  public function testAbsoluteRelative() {
+    $absolutes = [];
+    $absolutes['flag'] = Civi::url('backend://civicrm/admin', 'a');
+    $absolutes['method'] = Civi::url('backend://civicrm/admin')->setPreferFormat('absolute');
+
+    $relatives = [];
+    $relatives['default'] = Civi::url('backend://civicrm/admin');
+    $relatives['flag'] = Civi::url('backend://civicrm/admin', 'r');
+    $relatives['method'] = Civi::url('backend://civicrm/admin')->setPreferFormat('relative');
+
+    foreach ($absolutes as $key => $url) {
+      $this->assertRegExp(';^https?://;', (string) $url, "absolutes[$key] should be absolute URL");
+    }
+    foreach ($relatives as $key => $url) {
+      $this->assertNotRegExp(';^https?://;', (string) $url, "relatives[$key] should be relative URL");
+    }
+  }
+
+  public function testPath() {
+    $examples = [];
+    $examples[] = ['civicrm/ajax/api4', Civi::url('service://civicrm/ajax/api4')];
+    $examples[] = ['civicrm/ajax/api4/Contact/get', Civi::url('service://civicrm/ajax/api4')->addPath('Contact/get')];
+    $examples[] = ['civicrm/ajax/api4/Contact/get', Civi::url('service://civicrm/ajax/api4')->addPath('Contact')->addPath('get')];
+    $examples[] = ['civicrm/new-path', Civi::url('service://civicrm/old-path')->setPath('civicrm/new-path')];
+
+    foreach ($examples as $key => $example) {
+      /** @var \Civi\Core\Url $url */
+      [$expected, $url] = $example;
+      $this->assertEquals($expected, $url->getPath());
+      $this->assertStringContainsString($expected, (string) $url);
+    }
+  }
+
+  public function testQuery() {
+    $examples = [];
+    $examples[] = ['reset=1&id=9', Civi::url('frontend://civicrm/profile/view?reset=1&id=9')];
+    $examples[] = ['reset=1&id=9', Civi::url('frontend://civicrm/profile/view')->addQuery('reset=1&id=9')];
+    $examples[] = ['reset=1&id=9', Civi::url('frontend://civicrm/profile/view')->addQuery(['reset' => 1, 'id' => 9])];
+    $examples[] = ['noise=Hello+world%3F', Civi::url('frontend://civicrm/profile/view?noise=Hello+world%3F')];
+    $examples[] = ['noise=Hello+world%3F', Civi::url('frontend://civicrm/profile/view')->addQuery(['noise' => 'Hello world?'])];
+    $examples[] = ['reset=1&id=9', Civi::url('frontend://civicrm/profile/view?forget=this')->setQuery('reset=1&id=9')];
+    $examples[] = ['reset=1&id=9', Civi::url('frontend://civicrm/profile/view?forget=this')->setQuery('reset=1')->addQuery('id=9')];
+
+    foreach ($examples as $key => $example) {
+      /** @var \Civi\Core\Url $url */
+      [$expected, $url] = $example;
+      $this->assertEquals($expected, $url->getQuery());
+      $this->assertStringContainsString($expected, (string) $url);
+    }
+  }
+
+}
index 2fd0f4c121a0eedf73a589d8a4a39c46d22e11bd..28ce71e83baa93bed7f01c6b7c2bb73ee7848560 100644 (file)
@@ -68,6 +68,77 @@ class PathUrlTest extends \CiviEndToEndTestCase {
     }
   }
 
+  /**
+   * Get URLs through Civi::url().
+   *
+   * @see \Civi\Core\UrlTest
+   */
+  public function testUrl(): void {
+    // Make some requests for actual URLs
+    $this->assertUrlContentRegex(';MIT-LICENSE.txt;', \Civi::url('[civicrm.packages]/jquery/plugins/jquery.timeentry.js', 'a'));
+    $this->assertUrlContentRegex(';MIT-LICENSE.txt;', \Civi::url('asset://[civicrm.packages]/jquery/plugins/jquery.timeentry.js', 'a'));
+    $this->assertUrlContentRegex(';Please enter a valid email address;', \Civi::url('assetBuilder://crm-l10n.js?locale=en_US', 'a'));
+    $this->assertUrlContentRegex(';.module..crmSearchAdmin;', \Civi::url('ext://org.civicrm.search_kit/ang/crmSearchAdmin.module.js', 'a'));
+    $this->assertUrlContentRegex(';crm-section event_date_time-section;', \Civi::url('frontend://civicrm/event/info?id=1', 'a'));
+
+    // Check for well-formedness of some URLs
+    $urlPats = [];
+    switch (CIVICRM_UF) {
+      case 'Drupal':
+      case 'Drupal8':
+      case 'Backdrop':
+        $urlPats[] = [';/civicrm/event/info\?reset=1&id=9;', \Civi::url('frontend://civicrm/event/info?reset=1')->addQuery('id=9')];
+        $urlPats[] = [';/civicrm/admin\?reset=1;', \Civi::url('backend://civicrm/admin')->addQuery(['reset' => 1])];
+        break;
+
+      case 'WordPress':
+        $urlPats[] = [';civiwp=CiviCRM.*civicrm.*event.*info.*reset=1&id=9;', \Civi::url('frontend://civicrm/event/info?reset=1')->addQuery('id=9')];
+        $urlPats[] = [';/wp-admin.*civicrm.*admin.*reset=1;', \Civi::url('backend://civicrm/admin?reset=1')];
+        break;
+
+      case 'Joomla':
+        $urlPats[] = [';/index.php\?.*task=civicrm/event/info&reset=1&id=9;', \Civi::url('frontend://civicrm/event/inof?reset=1')->addQuery('id=9')];
+        $urlPats[] = [';/administrator/.*task=civicrm/admin/reset=1;', \Civi::url('backend://civicrm/admin')->addQuery('reset=1')];
+        break;
+
+      default:
+        $this->fail('Unrecognized UF: ' . CIVICRM_UF);
+    }
+
+    $urlPats[] = [';^https?://.*civicrm;', \Civi::url('frontend://civicrm/event/info?reset=1', 'a')];
+    $urlPats[] = [';^https://.*civicrm;', \Civi::url('frontend://civicrm/event/info?reset=1', 'as')];
+
+    // Some test-harnesses have HTTP_HOST. Some don't. It's pre-req for truly relative URLs.
+    if (!empty($_SERVER['HTTP_HOST'])) {
+      $urlPats[] = [';^/.*civicrm.*ajax.*api4.*Contact.*get;', \Civi::url('backend://civicrm/ajax/api4/Contact/get', 'r')];
+    }
+
+    $this->assertNotEmpty($urlPats);
+    foreach ($urlPats as $urlPat) {
+      $this->assertRegExp($urlPat[0], $urlPat[1]);
+    }
+  }
+
+  /**
+   * Check that 'frontend://', 'backend://', and 'current://' have the expected relations.
+   */
+  public function testUrl_FrontBackCurrent(): void {
+    $front = (string) \Civi::url('frontend://civicrm/profile/view');
+    $back = (string) \Civi::url('backend://civicrm/profile/view');
+    $current = (string) \Civi::url('current://civicrm/profile/view');
+    $this->assertStringContainsString('profile', $front);
+    $this->assertStringContainsString('profile', $back);
+    $this->assertStringContainsString('profile', $current);
+    if (CIVICRM_UF === 'WordPress' || CIVICRM_UF === 'Joomla') {
+      $this->assertNotEquals($front, $back, "On WordPress/Joomla, some URLs should support frontend+backend flavors.");
+    }
+    else {
+      $this->assertEquals($front, $back, "On Drupal/Backdrop/Standalone, frontend and backend URLs should look the same.");
+    }
+    $this->assertEquals($back, $current, "Within E2E tests, current routing style is backend.");
+    // For purposes of this test, it doesn't matter if "current" is frontend or backend - as long as it's consistent.
+  }
+
   /**
    * @param string $expectContentRegex
    * @param string $url