diff --git a/CRM/Stripe/Upgrader/Base.php b/CRM/Stripe/Upgrader/Base.php
index 0c0e68068883fbe6876046d160a1cf40943b7862..3749a4260994bc869ba5db12e51b8d7aed260590 100644
--- a/CRM/Stripe/Upgrader/Base.php
+++ b/CRM/Stripe/Upgrader/Base.php
@@ -1,6 +1,7 @@
 <?php
 
 // AUTO-GENERATED FILE -- Civix may overwrite any changes made to this file
+use CRM_Stripe_ExtensionUtil as E;
 
 /**
  * Base class which provides helpers to execute upgrade logic
@@ -8,7 +9,7 @@
 class CRM_Stripe_Upgrader_Base {
 
   /**
-   * @var varies, subclass of ttis
+   * @var varies, subclass of this
    */
   static $instance;
 
@@ -32,15 +33,21 @@ class CRM_Stripe_Upgrader_Base {
    */
   private $revisions;
 
+  /**
+   * @var boolean
+   *   Flag to clean up extension revision data in civicrm_setting
+   */
+  private $revisionStorageIsDeprecated = FALSE;
+
   /**
    * Obtain a reference to the active upgrade handler.
    */
   static public function instance() {
-    if (! self::$instance) {
+    if (!self::$instance) {
       // FIXME auto-generate
       self::$instance = new CRM_Stripe_Upgrader(
         'com.drastikbydesign.stripe',
-        realpath(__DIR__ .'/../../../')
+        realpath(__DIR__ . '/../../../')
       );
     }
     return self::$instance;
@@ -91,7 +98,6 @@ class CRM_Stripe_Upgrader_Base {
    * @return bool
    */
   protected static function executeCustomDataFileByAbsPath($xml_file) {
-    require_once 'CRM/Utils/Migrate/Import.php';
     $import = new CRM_Utils_Migrate_Import();
     $import->run($xml_file);
     return TRUE;
@@ -107,7 +113,26 @@ class CRM_Stripe_Upgrader_Base {
   public function executeSqlFile($relativePath) {
     CRM_Utils_File::sourceSQLFile(
       CIVICRM_DSN,
-      $this->extensionDir . '/' . $relativePath
+      $this->extensionDir . DIRECTORY_SEPARATOR . $relativePath
+    );
+    return TRUE;
+  }
+
+  /**
+   * @param string $tplFile
+   *   The SQL file path (relative to this extension's dir).
+   *   Ex: "sql/mydata.mysql.tpl".
+   * @return bool
+   */
+  public function executeSqlTemplate($tplFile) {
+    // Assign multilingual variable to Smarty.
+    $upgrade = new CRM_Upgrade_Form();
+
+    $tplFile = CRM_Utils_File::isAbsolute($tplFile) ? $tplFile : $this->extensionDir . DIRECTORY_SEPARATOR . $tplFile;
+    $smarty = CRM_Core_Smarty::singleton();
+    $smarty->assign('domainID', CRM_Core_Config::domainID());
+    CRM_Utils_File::sourceSQLFile(
+      CIVICRM_DSN, $smarty->fetch($tplFile), NULL, TRUE
     );
     return TRUE;
   }
@@ -121,7 +146,7 @@ class CRM_Stripe_Upgrader_Base {
    */
   public function executeSql($query, $params = array()) {
     // FIXME verify that we raise an exception on error
-    CRM_Core_DAO::executeSql($query, $params);
+    CRM_Core_DAO::executeQuery($query, $params);
     return TRUE;
   }
 
@@ -205,7 +230,7 @@ class CRM_Stripe_Upgrader_Base {
    * @return array(revisionNumbers) sorted numerically
    */
   public function getRevisions() {
-    if (! is_array($this->revisions)) {
+    if (!is_array($this->revisions)) {
       $this->revisions = array();
 
       $clazz = new ReflectionClass(get_class($this));
@@ -222,24 +247,42 @@ class CRM_Stripe_Upgrader_Base {
   }
 
   public function getCurrentRevision() {
-    // return CRM_Core_BAO_Extension::getSchemaVersion($this->extensionName);
+    $revision = CRM_Core_BAO_Extension::getSchemaVersion($this->extensionName);
+    if (!$revision) {
+      $revision = $this->getCurrentRevisionDeprecated();
+    }
+    return $revision;
+  }
+
+  private function getCurrentRevisionDeprecated() {
     $key = $this->extensionName . ':version';
-    return CRM_Core_BAO_Setting::getItem('Extension', $key);
+    if ($revision = CRM_Core_BAO_Setting::getItem('Extension', $key)) {
+      $this->revisionStorageIsDeprecated = TRUE;
+    }
+    return $revision;
   }
 
   public function setCurrentRevision($revision) {
-    // We call this during hook_civicrm_install, but the underlying SQL
-    // UPDATE fails because the extension record hasn't been INSERTed yet.
-    // Instead, track revisions in our own namespace.
-    // CRM_Core_BAO_Extension::setSchemaVersion($this->extensionName, $revision);
-
-    $key = $this->extensionName . ':version';
-    CRM_Core_BAO_Setting::setItem($revision, 'Extension', $key);
+    CRM_Core_BAO_Extension::setSchemaVersion($this->extensionName, $revision);
+    // clean up legacy schema version store (CRM-19252)
+    $this->deleteDeprecatedRevision();
     return TRUE;
   }
 
+  private function deleteDeprecatedRevision() {
+    if ($this->revisionStorageIsDeprecated) {
+      $setting = new CRM_Core_BAO_Setting();
+      $setting->name = $this->extensionName . ':version';
+      $setting->delete();
+      CRM_Core_Error::debug_log_message("Migrated extension schema revision ID for {$this->extensionName} from civicrm_setting (deprecated) to civicrm_extension.\n");
+    }
+  }
+
   // ******** Hook delegates ********
 
+  /**
+   * @see https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_install
+   */
   public function onInstall() {
     $files = glob($this->extensionDir . '/sql/*_install.sql');
     if (is_array($files)) {
@@ -247,6 +290,12 @@ class CRM_Stripe_Upgrader_Base {
         CRM_Utils_File::sourceSQLFile(CIVICRM_DSN, $file);
       }
     }
+    $files = glob($this->extensionDir . '/sql/*_install.mysql.tpl');
+    if (is_array($files)) {
+      foreach ($files as $file) {
+        $this->executeSqlTemplate($file);
+      }
+    }
     $files = glob($this->extensionDir . '/xml/*_install.xml');
     if (is_array($files)) {
       foreach ($files as $file) {
@@ -256,13 +305,31 @@ class CRM_Stripe_Upgrader_Base {
     if (is_callable(array($this, 'install'))) {
       $this->install();
     }
+  }
+
+  /**
+   * @see https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
+   */
+  public function onPostInstall() {
     $revisions = $this->getRevisions();
     if (!empty($revisions)) {
       $this->setCurrentRevision(max($revisions));
     }
+    if (is_callable(array($this, 'postInstall'))) {
+      $this->postInstall();
+    }
   }
 
+  /**
+   * @see https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
+   */
   public function onUninstall() {
+    $files = glob($this->extensionDir . '/sql/*_uninstall.mysql.tpl');
+    if (is_array($files)) {
+      foreach ($files as $file) {
+        $this->executeSqlTemplate($file);
+      }
+    }
     if (is_callable(array($this, 'uninstall'))) {
       $this->uninstall();
     }
@@ -272,9 +339,11 @@ class CRM_Stripe_Upgrader_Base {
         CRM_Utils_File::sourceSQLFile(CIVICRM_DSN, $file);
       }
     }
-    $this->setCurrentRevision(NULL);
   }
 
+  /**
+   * @see https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_enable
+   */
   public function onEnable() {
     // stub for possible future use
     if (is_callable(array($this, 'enable'))) {
@@ -282,6 +351,9 @@ class CRM_Stripe_Upgrader_Base {
     }
   }
 
+  /**
+   * @see https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
+   */
   public function onDisable() {
     // stub for possible future use
     if (is_callable(array($this, 'disable'))) {
@@ -300,4 +372,5 @@ class CRM_Stripe_Upgrader_Base {
       default:
     }
   }
+
 }
diff --git a/stripe.civix.php b/stripe.civix.php
index 6de525c8f17aa6577c5c659e1a7f3ed6e5569ad1..90b9159582121ef81bcc7753bd20ee3c3a17260f 100644
--- a/stripe.civix.php
+++ b/stripe.civix.php
@@ -24,9 +24,9 @@ class CRM_Stripe_ExtensionUtil {
    *   Translated text.
    * @see ts
    */
-  public static function ts($text, $params = array()) {
+  public static function ts($text, $params = []) {
     if (!array_key_exists('domain', $params)) {
-      $params['domain'] = array(self::LONG_NAME, NULL);
+      $params['domain'] = [self::LONG_NAME, NULL];
     }
     return ts($text, $params);
   }
@@ -82,7 +82,7 @@ use CRM_Stripe_ExtensionUtil as E;
 /**
  * (Delegated) Implements hook_civicrm_config().
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_config
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config
  */
 function _stripe_civix_civicrm_config(&$config = NULL) {
   static $configured = FALSE;
@@ -100,7 +100,7 @@ function _stripe_civix_civicrm_config(&$config = NULL) {
     array_unshift($template->template_dir, $extDir);
   }
   else {
-    $template->template_dir = array($extDir, $template->template_dir);
+    $template->template_dir = [$extDir, $template->template_dir];
   }
 
   $include_path = $extRoot . PATH_SEPARATOR . get_include_path();
@@ -112,7 +112,7 @@ function _stripe_civix_civicrm_config(&$config = NULL) {
  *
  * @param $files array(string)
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_xmlMenu
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_xmlMenu
  */
 function _stripe_civix_civicrm_xmlMenu(&$files) {
   foreach (_stripe_civix_glob(__DIR__ . '/xml/Menu/*.xml') as $file) {
@@ -123,7 +123,7 @@ function _stripe_civix_civicrm_xmlMenu(&$files) {
 /**
  * Implements hook_civicrm_install().
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_install
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_install
  */
 function _stripe_civix_civicrm_install() {
   _stripe_civix_civicrm_config();
@@ -135,12 +135,12 @@ function _stripe_civix_civicrm_install() {
 /**
  * Implements hook_civicrm_postInstall().
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_postInstall
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
  */
 function _stripe_civix_civicrm_postInstall() {
   _stripe_civix_civicrm_config();
   if ($upgrader = _stripe_civix_upgrader()) {
-    if (is_callable(array($upgrader, 'onPostInstall'))) {
+    if (is_callable([$upgrader, 'onPostInstall'])) {
       $upgrader->onPostInstall();
     }
   }
@@ -149,7 +149,7 @@ function _stripe_civix_civicrm_postInstall() {
 /**
  * Implements hook_civicrm_uninstall().
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_uninstall
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
  */
 function _stripe_civix_civicrm_uninstall() {
   _stripe_civix_civicrm_config();
@@ -161,12 +161,12 @@ function _stripe_civix_civicrm_uninstall() {
 /**
  * (Delegated) Implements hook_civicrm_enable().
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_enable
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_enable
  */
 function _stripe_civix_civicrm_enable() {
   _stripe_civix_civicrm_config();
   if ($upgrader = _stripe_civix_upgrader()) {
-    if (is_callable(array($upgrader, 'onEnable'))) {
+    if (is_callable([$upgrader, 'onEnable'])) {
       $upgrader->onEnable();
     }
   }
@@ -175,13 +175,13 @@ function _stripe_civix_civicrm_enable() {
 /**
  * (Delegated) Implements hook_civicrm_disable().
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_disable
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
  * @return mixed
  */
 function _stripe_civix_civicrm_disable() {
   _stripe_civix_civicrm_config();
   if ($upgrader = _stripe_civix_upgrader()) {
-    if (is_callable(array($upgrader, 'onDisable'))) {
+    if (is_callable([$upgrader, 'onDisable'])) {
       $upgrader->onDisable();
     }
   }
@@ -196,7 +196,7 @@ function _stripe_civix_civicrm_disable() {
  * @return mixed  based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending)
  *                for 'enqueue', returns void
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_upgrade
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_upgrade
  */
 function _stripe_civix_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
   if ($upgrader = _stripe_civix_upgrader()) {
@@ -217,22 +217,23 @@ function _stripe_civix_upgrader() {
 }
 
 /**
- * Search directory tree for files which match a glob pattern
+ * Search directory tree for files which match a glob pattern.
  *
  * Note: Dot-directories (like "..", ".git", or ".svn") will be ignored.
  * Note: In Civi 4.3+, delegate to CRM_Utils_File::findFiles()
  *
- * @param $dir string, base dir
- * @param $pattern string, glob pattern, eg "*.txt"
+ * @param string $dir base dir
+ * @param string $pattern , glob pattern, eg "*.txt"
+ *
  * @return array(string)
  */
 function _stripe_civix_find_files($dir, $pattern) {
-  if (is_callable(array('CRM_Utils_File', 'findFiles'))) {
+  if (is_callable(['CRM_Utils_File', 'findFiles'])) {
     return CRM_Utils_File::findFiles($dir, $pattern);
   }
 
-  $todos = array($dir);
-  $result = array();
+  $todos = [$dir];
+  $result = [];
   while (!empty($todos)) {
     $subdir = array_shift($todos);
     foreach (_stripe_civix_glob("$subdir/$pattern") as $match) {
@@ -259,7 +260,7 @@ function _stripe_civix_find_files($dir, $pattern) {
  *
  * Find any *.mgd.php files, merge their content, and return.
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_managed
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_managed
  */
 function _stripe_civix_civicrm_managed(&$entities) {
   $mgdFiles = _stripe_civix_find_files(__DIR__, '*.mgd.php');
@@ -285,7 +286,7 @@ function _stripe_civix_civicrm_managed(&$entities) {
  *
  * Note: This hook only runs in CiviCRM 4.4+.
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_caseTypes
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_caseTypes
  */
 function _stripe_civix_civicrm_caseTypes(&$caseTypes) {
   if (!is_dir(__DIR__ . '/xml/case')) {
@@ -296,14 +297,13 @@ function _stripe_civix_civicrm_caseTypes(&$caseTypes) {
     $name = preg_replace('/\.xml$/', '', basename($file));
     if ($name != CRM_Case_XMLProcessor::mungeCaseType($name)) {
       $errorMessage = sprintf("Case-type file name is malformed (%s vs %s)", $name, CRM_Case_XMLProcessor::mungeCaseType($name));
-      CRM_Core_Error::fatal($errorMessage);
-      // throw new CRM_Core_Exception($errorMessage);
+      throw new CRM_Core_Exception($errorMessage);
     }
-    $caseTypes[$name] = array(
+    $caseTypes[$name] = [
       'module' => E::LONG_NAME,
       'name' => $name,
       'file' => $file,
-    );
+    ];
   }
 }
 
@@ -314,7 +314,7 @@ function _stripe_civix_civicrm_caseTypes(&$caseTypes) {
  *
  * Note: This hook only runs in CiviCRM 4.5+.
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_angularModules
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_angularModules
  */
 function _stripe_civix_civicrm_angularModules(&$angularModules) {
   if (!is_dir(__DIR__ . '/ang')) {
@@ -332,6 +332,25 @@ function _stripe_civix_civicrm_angularModules(&$angularModules) {
   }
 }
 
+/**
+ * (Delegated) Implements hook_civicrm_themes().
+ *
+ * Find any and return any files matching "*.theme.php"
+ */
+function _stripe_civix_civicrm_themes(&$themes) {
+  $files = _stripe_civix_glob(__DIR__ . '/*.theme.php');
+  foreach ($files as $file) {
+    $themeMeta = include $file;
+    if (empty($themeMeta['name'])) {
+      $themeMeta['name'] = preg_replace(':\.theme\.php$:', '', basename($file));
+    }
+    if (empty($themeMeta['ext'])) {
+      $themeMeta['ext'] = E::LONG_NAME;
+    }
+    $themes[$themeMeta['name']] = $themeMeta;
+  }
+}
+
 /**
  * Glob wrapper which is guaranteed to return an array.
  *
@@ -342,11 +361,12 @@ function _stripe_civix_civicrm_angularModules(&$angularModules) {
  *
  * @link http://php.net/glob
  * @param string $pattern
+ *
  * @return array, possibly empty
  */
 function _stripe_civix_glob($pattern) {
   $result = glob($pattern);
-  return is_array($result) ? $result : array();
+  return is_array($result) ? $result : [];
 }
 
 /**
@@ -357,16 +377,18 @@ function _stripe_civix_glob($pattern) {
  *    'Mailing', or 'Administer/System Settings'
  * @param array $item - the item to insert (parent/child attributes will be
  *    filled for you)
+ *
+ * @return bool
  */
 function _stripe_civix_insert_navigation_menu(&$menu, $path, $item) {
   // If we are done going down the path, insert menu
   if (empty($path)) {
-    $menu[] = array(
-      'attributes' => array_merge(array(
+    $menu[] = [
+      'attributes' => array_merge([
         'label'      => CRM_Utils_Array::value('name', $item),
         'active'     => 1,
-      ), $item),
-    );
+      ], $item),
+    ];
     return TRUE;
   }
   else {
@@ -377,9 +399,9 @@ function _stripe_civix_insert_navigation_menu(&$menu, $path, $item) {
     foreach ($menu as $key => &$entry) {
       if ($entry['attributes']['name'] == $first) {
         if (!isset($entry['child'])) {
-          $entry['child'] = array();
+          $entry['child'] = [];
         }
-        $found = _stripe_civix_insert_navigation_menu($entry['child'], implode('/', $path), $item, $key);
+        $found = _stripe_civix_insert_navigation_menu($entry['child'], implode('/', $path), $item);
       }
     }
     return $found;
@@ -390,7 +412,7 @@ function _stripe_civix_insert_navigation_menu(&$menu, $path, $item) {
  * (Delegated) Implements hook_civicrm_navigationMenu().
  */
 function _stripe_civix_navigationMenu(&$nodes) {
-  if (!is_callable(array('CRM_Core_BAO_Navigation', 'fixNavigationMenu'))) {
+  if (!is_callable(['CRM_Core_BAO_Navigation', 'fixNavigationMenu'])) {
     _stripe_civix_fixNavigationMenu($nodes);
   }
 }
@@ -432,17 +454,11 @@ function _stripe_civix_fixNavigationMenuItems(&$nodes, &$maxNavID, $parentID) {
 /**
  * (Delegated) Implements hook_civicrm_alterSettingsFolders().
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_alterSettingsFolders
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_alterSettingsFolders
  */
 function _stripe_civix_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) {
-  static $configured = FALSE;
-  if ($configured) {
-    return;
-  }
-  $configured = TRUE;
-
   $settingsDir = __DIR__ . DIRECTORY_SEPARATOR . 'settings';
-  if (is_dir($settingsDir) && !in_array($settingsDir, $metaDataFolders)) {
+  if (!in_array($settingsDir, $metaDataFolders) && is_dir($settingsDir)) {
     $metaDataFolders[] = $settingsDir;
   }
 }
@@ -452,7 +468,7 @@ function _stripe_civix_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) {
  *
  * Find any *.entityType.php files, merge their content, and return.
  *
- * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_entityTypes
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
  */
 
 function _stripe_civix_civicrm_entityTypes(&$entityTypes) {
diff --git a/tests/phpunit/CRM/Stripe/BaseTest.php b/tests/phpunit/CRM/Stripe/BaseTest.php
index 3f444739e4158b6bd104fe3f90975152bc778d23..25c7b554593b743f2ae6118d9b63c6b27a67e43e 100644
--- a/tests/phpunit/CRM/Stripe/BaseTest.php
+++ b/tests/phpunit/CRM/Stripe/BaseTest.php
@@ -45,6 +45,7 @@ class CRM_Stripe_BaseTest extends \PHPUnit\Framework\TestCase implements Headles
     // Civi\Test has many helpers, like install(), uninstall(), sql(), and sqlFile().
     // See: https://github.com/civicrm/org.civicrm.testapalooza/blob/master/civi-test.md
     return \Civi\Test::headless()
+      ->install('mjwshared')
       ->installMe(__DIR__)
       ->apply();
   }
@@ -252,5 +253,4 @@ class CRM_Stripe_BaseTest extends \PHPUnit\Framework\TestCase implements Headles
     CRM_Utils_Cache::singleton()->flush();
   }
 
-
 }
diff --git a/tests/phpunit/CRM/Stripe/DirectTest.php b/tests/phpunit/CRM/Stripe/DirectTest.php
index a30ac64dc953eaac313c5ef9a33cb5762ae96a85..b15bd5d42a5b02bbccdc1755752a703d10865321 100644
--- a/tests/phpunit/CRM/Stripe/DirectTest.php
+++ b/tests/phpunit/CRM/Stripe/DirectTest.php
@@ -19,7 +19,7 @@ use Civi\Test\TransactionalInterface;
  * @group headless
  */
 require ('BaseTest.php');
-class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
+class CRM_Stripe_DirectTest extends CRM_Stripe_BaseTest {
 
   protected $_contributionRecurID;
   protected $_total = '200';
@@ -28,6 +28,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
     // Civi\Test has many helpers, like install(), uninstall(), sql(), and sqlFile().
     // See: https://github.com/civicrm/org.civicrm.testapalooza/blob/master/civi-test.md
     return \Civi\Test::headless()
+      ->install('mjwshared')
       ->installMe(__DIR__)
       ->apply();
   }
@@ -49,5 +50,4 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
     $this->assertValidTrxn();
   }
 
-   
 }
diff --git a/tests/phpunit/CRM/Stripe/IpnTest.php b/tests/phpunit/CRM/Stripe/IpnTest.php
index d616615290ddef0f4a30556f32ed7933f201db26..acbf30dbdade56e2837777f7f67e4d7a31d413d9 100644
--- a/tests/phpunit/CRM/Stripe/IpnTest.php
+++ b/tests/phpunit/CRM/Stripe/IpnTest.php
@@ -32,6 +32,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
   public function setUpHeadless() {
     $force = TRUE;
     return \Civi\Test::headless()
+      ->install('mjwshared')
       ->installMe(__DIR__)
       ->apply($force);
   }
@@ -298,4 +299,5 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
     $this->_contributionRecurID = $contributionRecur['id'];
     $this->_contributionID = $contributionRecur['values']['0']['api.contribution.create']['id'];
   }
+
 }