+--------------------------------------------------------------------+
*/
-
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
/**
*/
class CiviSeleniumTestCase extends PHPUnit_Extensions_SeleniumTestCase {
- // protected $coverageScriptUrl = 'http://tests.dev.civicrm.org/drupal/phpunit_coverage.php';
+ // Current logged-in user
+ protected $loggedInAs = NULL;
/**
* Constructor
*/
function __construct($name = NULL, array$data = array(), $dataName = '', array$browser = array()) {
parent::__construct($name, $data, $dataName, $browser);
+ $this->loggedInAs = NULL;
require_once 'CiviSeleniumSettings.php';
$this->settings = new CiviSeleniumSettings();
CRM_Core_ClassLoader::singleton()->register();
// also initialize a connection to the db
+ // FIXME: not necessary for most tests, consider moving into functions that need this
$config = CRM_Core_Config::singleton();
}
}
protected function tearDown() {
- // $this->open( $this->settings->sandboxPATH . "logout?reset=1");
}
/**
* Authenticate as drupal user
- * @param $admin: (bool) use admin user/pass instead of normal user
+ * @param $user: (str) the key 'user' or 'admin', or a literal username
+ * @param $pass: (str) if $user is a literal username and not 'user' or 'admin', supply the password
*/
- function webtestLogin($admin = FALSE) {
+ function webtestLogin($user = 'user', $pass = NULL) {
+ // If already logged in as correct user, do nothing
+ if ($this->loggedInAs === $user) {
+ return;
+ }
+ // If we are logged in as a different user, log out first
+ if ($this->loggedInAs) {
+ $this->webtestLogout();
+ }
$this->open("{$this->sboxPath}user");
- $password = $admin ? $this->settings->adminPassword : $this->settings->password;
- $username = $admin ? $this->settings->adminUsername : $this->settings->username;
+ // Lookup username & password if not supplied
+ $username = $user;
+ if ($pass === NULL) {
+ $pass = $user == 'admin' ? $this->settings->adminPassword : $this->settings->password;
+ $username = $user == 'admin' ? $this->settings->adminUsername : $this->settings->username;
+ }
// Make sure login form is available
$this->waitForElementPresent('edit-submit');
$this->type('edit-name', $username);
- $this->type('edit-pass', $password);
+ $this->type('edit-pass', $pass);
$this->click('edit-submit');
$this->waitForPageToLoad($this->getTimeoutMsec());
+ $this->loggedInAs = $user;
+ }
+
+ function webtestLogout() {
+ if ($this->loggedInAs) {
+ $this->open($this->sboxPath . "user/logout");
+ $this->waitForPageToLoad($this->getTimeoutMsec());
+ }
+ $this->loggedInAs = NULL;
}
/**
}
}
$this->open("{$this->sboxPath}civicrm/$url");
- $this->waitForPageToLoad();
+ $this->waitForPageToLoad($this->getTimeoutMsec());
+ if ($waitFor) {
+ $this->waitForElementPresent($waitFor);
+ }
+ }
+
+ /**
+ * Click on a link or button
+ * Wait for the page to load
+ * Wait for an element to be present
+ */
+ function clickLink($element, $waitFor = 'civicrm-footer', $waitForPageLoad = TRUE) {
+ $this->click($element);
+ // conditional wait for page load e.g for ajax form save
+ if ($waitForPageLoad) {
+ $this->waitForPageToLoad($this->getTimeoutMsec());
+ }
if ($waitFor) {
$this->waitForElementPresent($waitFor);
}
if ($added) {
$this->click("_qf_Component_next-bottom");
$this->waitForPageToLoad($this->getTimeoutMsec());
- $this->assertElementContainsText("crm-notification-container", "Saved");
+ $this->waitForText('crm-notification-container', "Saved");
}
}
function webtestAddHousehold($householdName = "Smith's Home", $email = NULL) {
- $this->open($this->sboxPath . 'civicrm/contact/add?reset=1&ct=Household');
+ $this->openCiviPage("contact/add", "reset=1&ct=Household");
$this->click('household_name');
$this->type('household_name', $householdName);
function webtestAddOrganization($organizationName = "Organization XYZ", $email = NULL) {
- $this->open($this->sboxPath . 'civicrm/contact/add?reset=1&ct=Organization');
+ $this->openCiviPage("contact/add", "reset=1&ct=Organization");
$this->click('organization_name');
$this->type('organization_name', $organizationName);
//$this->assertContains($sortName, $this->getValue('contact_1'), "autocomplete expected $sortName but didn’t find it in " . $this->getValue('contact_1'));
}
-
/*
* 1. By default, when no strtotime arg is specified, sets date to "now + 1 month"
* 2. Does not set time. For setting both date and time use webtestFillDateTime() method.
$this->runScript("CKEDITOR.instances['{$fieldName}'].setData('<p>{$text}</p>');");
}
elseif ($editor == 'TinyMCE') {
- $this->selectFrame("xpath=//iframe[@id='{$fieldName}_ifr']");
- $this->type("//html/body[@id='tinymce']", $text);
+ $this->waitForElementPresent("xpath=//iframe[@id='{$fieldName}_ifr']");
+ $this->runScript("tinyMCE.activeEditor.setContent('<p>{$text}</p>');");
}
else {
$this->fail("Unknown editor value: $editor, failing (in CiviSeleniumTestCase::fillRichTextField ...");
return $elements;
}
+ /**
+ * Returns a single argument from the url query
+ */
+ function urlArg($arg, $url = NULL) {
+ $elements = $this->parseURL($url);
+ return isset($elements['queryString'][$arg]) ? $elements['queryString'][$arg] : NULL;
+ }
+
/**
* Define a payment processor for use by a webtest. Default is to create Dummy processor
* which is useful for testing online public forms (online contribution pages and event registration)
* @return an array of saved params values.
*/
function webtestAddRelationshipType($params = array()) {
- $this->open($this->sboxPath . 'civicrm/admin/reltype?reset=1&action=add');
+ $this->openCiviPage("admin/reltype", "reset=1&action=add");
//build the params if not passed.
if (!is_array($params) || empty($params)) {
"Status message didn't show up after saving!"
);
- $this->open($this->sboxPath . 'civicrm/admin/reltype?reset=1');
- $this->waitForPageToLoad($this->getTimeoutMsec());
+ $this->openCiviPage("admin/reltype", "reset=1");
//validate data on selector.
$data = $params;
/**
* Create new online contribution page w/ user specified params or defaults.
+ * FIXME: this function take an absurd number of params - very unwieldy :(
*
* @param User can define pageTitle, hash and rand values for later data verification
*
}
// go to the New Contribution Page page
- $this->open($this->sboxPath . 'civicrm/admin/contribute?action=add&reset=1');
- $this->waitForPageToLoad();
+ $this->openCiviPage('admin/contribute', 'action=add&reset=1');
// fill in step 1 (Title and Settings)
$this->type('title', $pageTitle);
$this->click("id=is_confirm_enabled");
}
- // go to step 2
- $this->click('_qf_Settings_next');
- $this->waitForElementPresent('_qf_Amount_next-bottom');
+ // Submit form
+ $this->clickLink('_qf_Settings_next', "_qf_Amount_next-bottom");
+
+ // Get contribution page id
+ $pageId = $this->urlArg('id');
// fill in step 2 (Processor, Pay Later, Amounts)
if (!empty($processor)) {
$this->click('is_separate_payment');
}
}
- $this->click('_qf_MembershipBlock_next');
- $this->waitForPageToLoad($this->getTimeoutMsec());
- $this->waitForElementPresent('_qf_MembershipBlock_next-bottom');
+ $this->clickLink('_qf_MembershipBlock_next', '_qf_MembershipBlock_next-bottom');
$text = "'MembershipBlock' information has been saved.";
$this->assertTrue($this->isTextPresent($text), 'Missing text: ' . $text);
}
$this->assertTrue($this->isTextPresent($text), 'Missing text: ' . $text);
}
-
if ($widget) {
// fill in step 8 (Widget Settings)
$this->click('link=Widgets');
$this->assertTrue($this->isTextPresent($text), 'Missing text: ' . $text);
}
- // parse URL to grab the contribution page id
- $elements = $this->parseURL();
- $pageId = $elements['queryString']['id'];
-
- // pass $pageId back to any other tests that call this class
return $pageId;
}
}
}
- $this->open($this->sboxPath . 'civicrm/contact/deduperules?action=update&id=' . $strictRuleId);
- $this->waitForPageToLoad($this->getTimeoutMsec());
- $this->waitForElementPresent('_qf_DedupeRules_next-bottom');
+ $this->openCiviPage('contact/deduperules', "action=update&id=$strictRuleId", '_qf_DedupeRules_next-bottom');
$count = 0;
foreach ($fields as $field => $weight) {
'period_type' => $period_type,
);
- $this->open($this->sboxPath . 'civicrm/admin/member/membershipType/add?action=add&reset=1');
- $this->waitForElementPresent('_qf_MembershipType_cancel-bottom');
+ $this->openCiviPage("admin/member/membershipType/add", "action=add&reset=1", '_qf_MembershipType_cancel-bottom');
$this->type('name', $memTypeParams['membership_type']);
}
// Clicking save.
- $this->click('_qf_Edit_upload-bottom');
- $this->waitForPageToLoad($this->getTimeoutMsec());
+ $this->clickLink('_qf_Edit_upload-bottom');
// Is status message correct?
- $this->assertElementContainsText('crm-notification-container', "$groupName");
+ $this->waitForText('crm-notification-container', "$groupName");
return $groupName;
}
$firstName2 = substr(sha1(rand()), 0, 7);
$this->webtestAddContact($firstName2, "Anderson", $firstName2 . "@anderson.name");
- // Go directly to the URL of the screen that you will be testing (Activity Tab).
$this->click("css=li#tab_activity a");
// waiting for the activity dropdown to show up
// click through to the Activity view screen
$this->click("xpath=//div[@id='Activities']//table/tbody/tr[2]/td[9]/span/a[text()='View']");
$this->waitForElementPresent('_qf_Activity_cancel-bottom');
- $elements = $this->parseURL();
- $activityID = $elements['queryString']['id'];
- return $activityID;
+
+ // parse URL to grab the activity id
+ // pass id back to any other tests that call this class
+ return $this->urlArg('id');
}
static
return $this->assertInternalType($expected, $actual, $message);
}
- function changeAdminLinks() {
- $version = 7;
- if ($version == 7) {
- $this->open("{$this->sboxPath}admin/people/permissions");
- }
- else {
- $this->open("{$this->sboxPath}admin/user/permissions");
- }
- }
-
-
/**
* Add new Financial Account
*/
-
function _testAddFinancialAccount($financialAccountTitle,
$financialAccountDescription = FALSE,
$accountingCode = FALSE,
$isDefault = FALSE
) {
- // Go directly to the URL
- $this->open($this->sboxPath . "civicrm/admin/financial/financialAccount?reset=1");
- $this->waitForPageToLoad($this->getTimeoutMsec());
+ $this->openCiviPage("admin/financial/financialAccount", "reset=1");
$this->click("link=Add Financial Account");
$this->waitForElementPresent('_qf_FinancialAccount_cancel-botttom');
$this->waitForPageToLoad($this->getTimeoutMsec());
}
-
/**
* Edit Financial Account
*/
$isDefault = FALSE
) {
if ($firstName) {
- $this->open($this->sboxPath . "civicrm/admin/financial/financialAccount?reset=1");
- $this->waitForPageToLoad($this->getTimeoutMsec());
+ $this->openCiviPage("admin/financial/financialAccount", "reset=1");
}
$this->waitForElementPresent("xpath=//table/tbody//tr/td[1][text()='{$editfinancialAccount}']/../td[9]/span/a[text()='Edit']");
- $this->click("xpath=//table/tbody//tr/td[1][text()='{$editfinancialAccount}']/../td[9]/span/a[text()='Edit']");
- $this->waitForPageToLoad($this->getTimeoutMsec());
-
- $this->waitForElementPresent('_qf_FinancialAccount_cancel-botttom');
+ $this->clickLink("xpath=//table/tbody//tr/td[1][text()='{$editfinancialAccount}']/../td[9]/span/a[text()='Edit']", '_qf_FinancialAccount_cancel-botttom');
// Change Financial Account Name
if ($financialAccountTitle) {
$this->type('accounting_code', $accountingCode);
}
-
// Autofill Edit Organization
if ($firstName) {
$this->webtestOrganisationAutocomplete($firstName);
$this->waitForPageToLoad($this->getTimeoutMsec());
}
-
/**
* Delete Financial Account
*/
}
function addeditFinancialType($financialType, $option = 'new') {
- $this->open($this->sboxPath . 'civicrm/admin/financial/financialType?reset=1');
+ $this->openCiviPage("admin/financial/financialType", "reset=1");
if ($option == 'Delete') {
$this->click("xpath=id('ltype')/div/table/tbody/tr/td[1][text()='$financialType[name]']/../td[7]/span[2]");
$this->assertTrue($this->isTextPresent($text), 'Missing text: ' . $text);
}
-
+ /**
+ * Give the specified permissions
+ * Note: this function logs in as 'admin' (logging out if necessary)
+ */
function changePermissions($permission) {
- $this->open($this->sboxPath . "civicrm/logout?reset=1");
- $this->waitForPageToLoad($this->getTimeoutMsec());
- $this->webtestLogin(TRUE);
- $this->changeAdminLinks();
+ $this->webtestLogin('admin');
+ $this->open("{$this->sboxPath}admin/people/permissions");
$this->waitForElementPresent('edit-submit');
- foreach ((array) $permission as $key => $value) {
- $this->check($value);
+ foreach ((array) $permission as $perm) {
+ $this->check($perm);
}
$this->click('edit-submit');
$this->waitForPageToLoad($this->getTimeoutMsec());
$this->assertTrue($this->isTextPresent('The changes have been saved.'));
- $this->open($this->sboxPath . "user/logout");
- $this->waitForPageToLoad($this->getTimeoutMsec());
- $this->webtestLogin();
}
function addProfile($profileTitle, $profileFields) {
- // Go directly to the URL of the screen that you will be testing (New Profile).
- $this->open($this->sboxPath . "civicrm/admin/uf/group?reset=1");
+ $this->openCiviPage('admin/uf/group', "reset=1");
- $this->waitForPageToLoad($this->getTimeoutMsec());
$this->click('link=Add Profile');
// Add membership custom data field to profile
);
$this->select('account_relationship', "label={$accountRelationship}");
+ // Because it tends to cause problems, all uses of sleep() must be justified in comments
+ // Sleep should never be used for wait for anything to load from the server
+ // Justification for this instance: FIXME
sleep(2);
$this->select('financial_account_id', "label={$financialAccountTitle}");
$this->click('_qf_FinancialTypeAccount_next');
}
function addPaymentInstrument($label, $financialAccount) {
- $this->open($this->sboxPath . "civicrm/admin/options/payment_instrument?group=payment_instrument&action=add&reset=1");
- $this->waitForElementPresent("_qf_Options_next-bottom");
+ $this->openCiviPage('admin/options/payment_instrument', 'group=payment_instrument&action=add&reset=1', "_qf_Options_next-bottom");
$this->type("label", $label);
$this->select("financial_account_id", "value=$financialAccount");
$this->click("_qf_Options_next-bottom");
$this->waitForPageToLoad($this->getTimeoutMsec());
}
+ /**
+ * Ensure we have a default mailbox set up for CiviMail
+ */
+ function setupDefaultMailbox() {
+ $this->openCiviPage('admin/mailSettings', 'action=update&id=1&reset=1');
+ // Check if it hasn't already been set up
+ if (!$this->getSelectedValue('protocol')) {
+ $this->type('name', 'Test Domain');
+ $this->select('protocol', "IMAP");
+ $this->type('server', 'localhost');
+ $this->type('domain', 'example.com');
+ $this->click('_qf_MailSettings_next-top');
+ $this->waitForPageToLoad($this->getTimeoutMsec());
+ }
+ }
+
/**
* Determine the default time-out in milliseconds.
*
$timeout = ($this->settings && @$this->settings->timeout) ? ($this->settings->timeout * 1000) : 30000;
return (string) $timeout; // don't know why, but all our old code used a string
}
-}
+ /**
+ * CRM-12378
+ * checks custom fields rendering / loading properly on the fly WRT entity passed as parameter
+ *
+ *
+ * @param array $customSets custom sets i.e entity wise sets want to be created and checked
+ e.g $customSets = array(array('entity' => 'Contribution', 'subEntity' => 'Donation',
+ 'triggerElement' => $triggerElement))
+ array $triggerElement: the element which is responsible for custom group to load
+
+ which uses the entity info as its selection value
+ * @param array $pageUrl the url which on which the ajax custom group load takes place
+ * @return void
+ */
+ function customFieldSetLoadOnTheFlyCheck($customSets, $pageUrl) {
+ //add the custom set
+ $return = $this->addCustomGroupField($customSets);
+
+ $this->openCiviPage($pageUrl['url'], $pageUrl['args']);
+
+ foreach($return as $values) {
+ foreach ($values as $entityType => $customData) {
+ //initiate necessary variables
+ list($entity, $entityData) = explode('_', $entityType);
+ $elementType = CRM_Utils_Array::value('type', $customData['triggerElement'], 'select');
+ $elementName = CRM_Utils_Array::value('name', $customData['triggerElement']);
+ if ($elementType == 'select') {
+ //reset the select box, so triggering of ajax only happens
+ //WRT input of value in this function
+ $this->select($elementName, "index=0");
+ }
+ if (!empty($entityData)) {
+ if ($elementType == 'select') {
+ $this->select($elementName, "label=regexp:{$entityData}");
+ }
+ elseif ($elementType == 'checkbox') {
+ $val = explode(',', $entityData);
+ foreach($val as $v) {
+ $checkId = $this->getAttribute("xpath=//label[text()='{$v}']/@for");
+ $this->check($checkId);
+ }
+ }
+ }
+
+ //sleep method is used as to wait for custom field div to load -
+ //we cant use wait for the div element as we are asserting for the same,
+ //so wait for some time till the div loads
+ sleep(1);
+
+ //checking for proper custom data which is loading through ajax
+ $this->assertElementPresent("xpath=//div[@id='{$customData['cgtitle']}'][@class='crm-accordion-body']",
+ "The on the fly custom group has not been rendered for entity : {$entity} => {$entityData}");
+ $this->assertElementPresent("xpath=//div[@id='{$customData['cgtitle']}'][@class='crm-accordion-body']/table/tbody/tr/td[2]/input",
+ "The on the fly custom group field is not present for entity : {$entity} => {$entityData}");
+ }
+ }
+ }
+
+ function addCustomGroupField($customSets) {
+ foreach ($customSets as $customSet) {
+ $this->openCiviPage("admin/custom/group", "action=add&reset=1");
+
+ //fill custom group title
+ $customGroupTitle = "webtest_for_ajax_cd" . substr(sha1(rand()), 0, 4);
+ $this->click("title");
+ $this->type("title", $customGroupTitle);
+
+ //custom group extends
+ $this->click("extends_0");
+ $this->select("extends_0", "value={$customSet['entity']}");
+ if (!empty($customSet['subEntity'])) {
+ $this->addSelection("extends_1", "label={$customSet['subEntity']}");
+ }
+
+ // Don't collapse
+ $this->uncheck('collapse_display');
+
+ // Save
+ $this->click('_qf_Group_next-bottom');
+ $this->waitForElementPresent('_qf_Field_cancel-bottom');
+
+ //Is custom group created?
+ $this->waitForText('crm-notification-container', "Your custom field set '{$customGroupTitle}' has been added.");
+ $gid = $this->urlArg('gid');
+
+ $fieldLabel = "custom_field_for_{$customSet['entity']}_{$customSet['subEntity']}" . substr(sha1(rand()), 0, 4);
+ $this->type('label', $fieldLabel);
+ $this->click('_qf_Field_next-bottom');
+ $this->waitForPageToLoad($this->getTimeoutMsec());
+ $customGroupTitle = preg_replace('/\s/', '_', trim($customGroupTitle));
+
+ $return[] = array(
+ "{$customSet['entity']}_{$customSet['subEntity']}" => array('cgtitle' => $customGroupTitle, 'gid' => $gid, 'triggerElement' => $customSet['triggerElement']));
+ }
+ return $return;
+ }
+}
\ No newline at end of file