| 1 | <?php |
| 2 | /* |
| 3 | +--------------------------------------------------------------------+ |
| 4 | | CiviCRM version 4.7 | |
| 5 | +--------------------------------------------------------------------+ |
| 6 | | Copyright CiviCRM LLC (c) 2004-2016 | |
| 7 | +--------------------------------------------------------------------+ |
| 8 | | This file is a part of CiviCRM. | |
| 9 | | | |
| 10 | | CiviCRM is free software; you can copy, modify, and distribute it | |
| 11 | | under the terms of the GNU Affero General Public License | |
| 12 | | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. | |
| 13 | | | |
| 14 | | CiviCRM is distributed in the hope that it will be useful, but | |
| 15 | | WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
| 17 | | See the GNU Affero General Public License for more details. | |
| 18 | | | |
| 19 | | You should have received a copy of the GNU Affero General Public | |
| 20 | | License along with this program; if not, contact CiviCRM LLC | |
| 21 | | at info[AT]civicrm[DOT]org. If you have questions about the | |
| 22 | | GNU Affero General Public License or the licensing of CiviCRM, | |
| 23 | | see the CiviCRM license FAQ at http://civicrm.org/licensing | |
| 24 | +--------------------------------------------------------------------+ |
| 25 | */ |
| 26 | |
| 27 | require_once 'CiviTest/CiviSeleniumTestCase.php'; |
| 28 | |
| 29 | /** |
| 30 | * Class WebTest_Contact_InlineFieldsEditTest |
| 31 | */ |
| 32 | class WebTest_Contact_InlineFieldsEditTest extends CiviSeleniumTestCase { |
| 33 | |
| 34 | protected function setUp() { |
| 35 | parent::setUp(); |
| 36 | } |
| 37 | |
| 38 | public function testAddAndEditField() { |
| 39 | $this->webtestLogin(); |
| 40 | |
| 41 | // Add a contact |
| 42 | $firstName = 'WebTest' . substr(sha1(rand()), 0, 7); |
| 43 | $lastName = 'InlineFieldsEdit' . substr(sha1(rand()), 0, 7); |
| 44 | $this->webtestAddContact($firstName, $lastName); |
| 45 | $contactId = $this->urlArg('cid'); |
| 46 | $this->waitForElementPresent('css=.crm-inline-edit-container.crm-edit-ready'); |
| 47 | |
| 48 | // Set Communication Prefs |
| 49 | $this->inlineEdit('crm-communication-pref-content', array( |
| 50 | 'email_greeting_id' => TRUE, |
| 51 | 'privacy_do_not_email' => 1, |
| 52 | 'preferred_communication_method_1' => 1, |
| 53 | 'preferred_communication_method_2' => 1, |
| 54 | ), 'keep_open'); |
| 55 | $this->waitForElementPresent('css=.icon.privacy-flag.do-not-email'); |
| 56 | $this->inlineEdit('crm-communication-pref-content', array( |
| 57 | 'privacy_do_not_phone' => 1, |
| 58 | 'privacy_do_not_email' => 0, |
| 59 | 'preferred_communication_method_1' => 0, |
| 60 | 'preferred_communication_method_2' => 0, |
| 61 | ), 'keep_open'); |
| 62 | $this->waitForElementPresent('css=.icon.privacy-flag.do-not-phone'); |
| 63 | $this->inlineEdit('crm-communication-pref-content', array( |
| 64 | 'email_greeting_custom' => 'Hey You!', |
| 65 | ), 'no_open'); |
| 66 | $this->assertElementNotPresent('css=.icon.privacy-flag.do-not-email'); |
| 67 | |
| 68 | // Custom data |
| 69 | $this->click('css=div.crm-custom-set-block-1 .collapsible-title'); |
| 70 | $this->waitForAjaxContent(); |
| 71 | $this->openInlineForm('custom-set-content-1'); |
| 72 | $dateFieldId = $this->getAttribute("xpath=//table[@class='form-layout-compressed']/tbody/tr[3]/td[@class='html-adjust']/span/input@id"); |
| 73 | $this->inlineEdit('custom-set-content-1', array( |
| 74 | 'CIVICRM_QFID_Edu_2' => 1, |
| 75 | "//table[@class='form-layout-compressed']/tbody/tr[2]/td[@class='html-adjust']/select" => array('Single'), |
| 76 | $dateFieldId => 'date: now - 10 years', |
| 77 | )); |
| 78 | |
| 79 | // Edit contact info |
| 80 | $params = array( |
| 81 | 'job_title' => 'jobtest123', |
| 82 | 'nick_name' => 'nicktest123', |
| 83 | 'contact_source' => 'sourcetest123', |
| 84 | ); |
| 85 | $this->inlineEdit('crm-contactinfo-content', $params, 'keep_open'); |
| 86 | // Clear fields and verify they are deleted |
| 87 | $this->inlineEdit('crm-contactinfo-content', array( |
| 88 | 'job_title' => '', |
| 89 | 'nick_name' => '', |
| 90 | 'contact_source' => '', |
| 91 | ), 'no_open'); |
| 92 | foreach ($params as $str) { |
| 93 | $this->assertElementNotContainsText('crm-contactinfo-content', $str); |
| 94 | } |
| 95 | |
| 96 | // Add a phone |
| 97 | $this->inlineEdit('crm-phone-content', array( |
| 98 | 'phone_1_phone' => '123-456-7890', |
| 99 | 'phone_1_phone_ext' => '101', |
| 100 | 'phone_1_location_type_id' => array('Work'), |
| 101 | 'phone_1_phone_type_id' => array('Mobile'), |
| 102 | )); |
| 103 | |
| 104 | // Add im |
| 105 | $this->inlineEdit('crm-im-content', array( |
| 106 | 'im_1_name' => 'testmeout', |
| 107 | 'im_1_location_type_id' => array('Work'), |
| 108 | 'im_1_provider_id' => array('Jabber'), |
| 109 | )); |
| 110 | |
| 111 | // Add an address - should default to home |
| 112 | $this->inlineEdit('address-block-1', array( |
| 113 | 'address_1_street_address' => '123 St', |
| 114 | 'address_1_city' => 'San Somewhere', |
| 115 | ), 'keep_open'); |
| 116 | // Try to uncheck is_primary, we should get an error and it should stay checked |
| 117 | $this->click('address[1][is_primary]'); |
| 118 | $this->waitForElementPresent('css=#crm-notification-container .error.ui-notify-message'); |
| 119 | $this->assertChecked('address[1][is_primary]'); |
| 120 | // Try to open another form while this one is still open - nothing should happen |
| 121 | $this->waitForElementPresent('address-block-2'); |
| 122 | $this->openInlineForm('address-block-2', FALSE); |
| 123 | $this->assertElementNotPresent('css#address-block-2.form'); |
| 124 | // Update address |
| 125 | $this->inlineEdit('address-block-1', array( |
| 126 | 'address_1_street_address' => '321 Other St', |
| 127 | 'address_1_city' => 'Sans Nowhere', |
| 128 | 'address_1_postal_code' => '99999', |
| 129 | 'address_1_postal_code_suffix' => '99', |
| 130 | ), 'no_open'); |
| 131 | // Another address with same location type as first - should give an error |
| 132 | $this->inlineEdit('address-block-2', array( |
| 133 | 'address_2_street_address' => '123 Foo', |
| 134 | 'address_2_city' => 'San Anywhere', |
| 135 | 'address_2_location_type_id' => array('Home'), |
| 136 | ), 'error'); |
| 137 | $this->waitForTextPresent('required'); |
| 138 | // Share address with a new org |
| 139 | $this->click('address[2][use_shared_address]'); |
| 140 | $orgName = 'Test Org Inline' . substr(sha1(rand()), 0, 7); |
| 141 | |
| 142 | // create new organization with dialog |
| 143 | $this->clickAt("xpath=//div[@id='s2id_address_2_master_contact_id']/a"); |
| 144 | $this->click("xpath=//li[@class='select2-no-results']//a[contains(text(),' New Organization')]"); |
| 145 | $this->waitForElementPresent("css=div#crm-profile-block"); |
| 146 | $this->waitForElementPresent("_qf_Edit_next"); |
| 147 | |
| 148 | $this->type('organization_name', $orgName); |
| 149 | $this->type('street_address-1', 'Test Org Street'); |
| 150 | $this->type('city-1', 'Test Org City'); |
| 151 | $this->clickLink('_qf_Edit_next', 'selected_shared_address-2', FALSE); |
| 152 | $this->waitForTextPresent('Test Org Street'); |
| 153 | $this->inlineEdit('address-block-2', array( |
| 154 | 'address_2_location_type_id' => array('Work'), |
| 155 | ), 'no_open'); |
| 156 | $this->waitForElementPresent('css=.crm-content.crm-contact-current_employer'); |
| 157 | $this->assertElementContainsText('crm-contactinfo-content', $orgName); |
| 158 | $this->assertElementContainsText('address-block-2', $orgName); |
| 159 | $this->assertElementContainsText('address-block-2', 'Work Address'); |
| 160 | |
| 161 | // Edit demographics |
| 162 | $this->inlineEdit('crm-demographic-content', array( |
| 163 | "xpath=//div[@class='crm-clear']/div[1]/div[@class='crm-content']/label[text()='Female']" => TRUE, |
| 164 | 'is_deceased' => 1, |
| 165 | 'birth_date' => 'date: Jan 1 1970', |
| 166 | ), 'no_open'); |
| 167 | $this->assertElementContainsText('crm-demographic-content', 'Female'); |
| 168 | $this->assertElementContainsText('crm-demographic-content', 'Contact is Deceased'); |
| 169 | $this->inlineEdit('crm-demographic-content', array( |
| 170 | 'is_deceased' => 0, |
| 171 | ), 'no_open'); |
| 172 | $age = date('Y') - 1970; |
| 173 | $this->assertElementContainsText('crm-demographic-content', "$age years"); |
| 174 | |
| 175 | // Add emails |
| 176 | $this->inlineEdit('crm-email-content', array( |
| 177 | 'css=#crm-email-content a.add-more-inline' => TRUE, |
| 178 | 'email_1_email' => 'test1@monkey.com', |
| 179 | 'email_2_email' => 'test2@monkey.com', |
| 180 | ), 'keep_open'); |
| 181 | |
| 182 | // Try an invalid email |
| 183 | $this->inlineEdit('crm-email-content', array( |
| 184 | 'email_2_email' => 'invalid@monkey,com', |
| 185 | ), 'errorJs'); |
| 186 | |
| 187 | // Delete email |
| 188 | $this->inlineEdit('crm-email-content', array( |
| 189 | 'css=#Email_Block_2 a.crm-delete-inline' => TRUE, |
| 190 | )); |
| 191 | $this->assertElementNotContainsText('crm-email-content', 'test2@monkey.com'); |
| 192 | |
| 193 | // Add website with invalid url |
| 194 | $this->inlineEdit('crm-website-content', array( |
| 195 | 'css=#crm-website-content a.add-more-inline' => TRUE, |
| 196 | 'website_1_url' => 'http://example.com', |
| 197 | 'website_2_url' => 'something.wrong', |
| 198 | ), 'errorJs'); |
| 199 | |
| 200 | // Correct invalid url and add a third website |
| 201 | $this->inlineEdit('crm-website-content', array( |
| 202 | 'css=#crm-website-content a.add-more-inline' => TRUE, |
| 203 | 'website_2_url' => 'http://example.net', |
| 204 | 'website_2_website_type_id' => array('Work'), |
| 205 | 'website_3_url' => 'http://example.biz', |
| 206 | 'website_3_website_type_id' => array('Main'), |
| 207 | ), 'keep_open'); |
| 208 | |
| 209 | // Delete website |
| 210 | $this->inlineEdit('crm-website-content', array( |
| 211 | 'css=#Website_Block_2 a.crm-delete-inline' => TRUE, |
| 212 | )); |
| 213 | $this->assertElementNotContainsText('crm-website-content', 'http://example.net'); |
| 214 | |
| 215 | // Change contact name |
| 216 | $this->inlineEdit('crm-contactname-content', array( |
| 217 | 'first_name' => 'NewName', |
| 218 | 'prefix_id' => array('Mr.'), |
| 219 | )); |
| 220 | $this->assertElementContainsText('css=div.crm-summary-display_name', "Mr. NewName $lastName"); |
| 221 | // Page title should be updated with new name on reload |
| 222 | $this->openCiviPage('contact/view', "reset=1&cid=$contactId", "crm-record-log"); |
| 223 | $this->assertElementContainsText('css=title', "Mr. NewName $lastName"); |
| 224 | } |
| 225 | |
| 226 | /** |
| 227 | * Click on an inline-edit block and wait for it to open |
| 228 | * |
| 229 | * @param string $block |
| 230 | * selector. |
| 231 | * @param bool $wait |
| 232 | */ |
| 233 | private function openInlineForm($block, $wait = TRUE) { |
| 234 | $this->mouseDown($block); |
| 235 | $this->mouseUp($block); |
| 236 | if ($wait) { |
| 237 | $this->waitForElementPresent("css=#$block .crm-container-snippet form"); |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | /** |
| 242 | * Enter values in an inline edit block and save. |
| 243 | * |
| 244 | * @param string $block |
| 245 | * selector. |
| 246 | * @param array $params |
| 247 | * @param \str|string $valid str: submit behavior |
| 248 | * 'error' if we are expecting a form validation error, |
| 249 | * 're_open' (default) after saving, opens the form and validate inputs |
| 250 | * 'keep_open' same as 're_open' but doesn't automatically cancel at the end |
| 251 | * 'no_open' do not re-open to validate |
| 252 | */ |
| 253 | private function inlineEdit($block, $params, $valid = 're_open') { |
| 254 | $this->openInlineForm($block); |
| 255 | foreach ($params as $item => $val) { |
| 256 | switch (gettype($val)) { |
| 257 | case 'boolean': |
| 258 | $this->click($item); |
| 259 | break; |
| 260 | |
| 261 | case 'string': |
| 262 | if (substr($val, 0, 5) == 'date:') { |
| 263 | $this->webtestFillDate($item, trim(substr($val, 5))); |
| 264 | } |
| 265 | else { |
| 266 | $this->type($item, $val); |
| 267 | } |
| 268 | break; |
| 269 | |
| 270 | case 'integer': |
| 271 | $method = $val ? 'check' : 'uncheck'; |
| 272 | $this->$method($item); |
| 273 | break; |
| 274 | |
| 275 | case 'array': |
| 276 | foreach ($val as $option) { |
| 277 | $selector = is_int($option) ? 'value' : 'label'; |
| 278 | $this->select($item, "$selector=$option"); |
| 279 | } |
| 280 | break; |
| 281 | } |
| 282 | } |
| 283 | $this->click("css=#$block input.crm-form-submit"); |
| 284 | if ($valid !== 'error' && $valid != 'errorJs') { |
| 285 | // Verify the form saved |
| 286 | $this->waitForElementPresent("css=#$block > .crm-inline-block-content"); |
| 287 | $validate = FALSE; |
| 288 | foreach ($params as $val) { |
| 289 | if (is_string($val) && $val && substr($val, 0, 5) != 'date:') { |
| 290 | $this->assertElementContainsText($block, $val); |
| 291 | $validate = TRUE; |
| 292 | } |
| 293 | elseif (!is_bool($val)) { |
| 294 | $validate = TRUE; |
| 295 | } |
| 296 | if (is_array($val)) { |
| 297 | foreach ($val as $option) { |
| 298 | if (!is_int($option)) { |
| 299 | $this->assertElementContainsText($block, $option); |
| 300 | } |
| 301 | } |
| 302 | } |
| 303 | } |
| 304 | // Open the form back up and check everything |
| 305 | if ($validate && $valid !== 'no_open') { |
| 306 | $this->openInlineForm($block); |
| 307 | foreach ($params as $item => $val) { |
| 308 | switch (gettype($val)) { |
| 309 | case 'string': |
| 310 | if ($val && substr($val, 0, 5) == 'date:') { |
| 311 | $val = date('m/d/Y', strtotime(trim(substr($val, 5)))); |
| 312 | $item = "xpath=//input[@id='{$item}']/following-sibling::input"; |
| 313 | } |
| 314 | if ($val) { |
| 315 | $this->assertElementValueEquals($item, $val); |
| 316 | } |
| 317 | break; |
| 318 | |
| 319 | case 'integer': |
| 320 | $method = $val ? 'assertChecked' : 'assertNotChecked'; |
| 321 | $this->$method($item); |
| 322 | break; |
| 323 | |
| 324 | case 'array': |
| 325 | foreach ($val as $option) { |
| 326 | $method = is_int($option) ? 'assertIsSelected' : 'assertSelected'; |
| 327 | $this->$method($item, $option); |
| 328 | } |
| 329 | break; |
| 330 | } |
| 331 | } |
| 332 | if ($valid !== 'keep_open') { |
| 333 | $this->click("css=#$block input.cancel"); |
| 334 | } |
| 335 | } |
| 336 | } |
| 337 | // Verify there was a form error |
| 338 | else { |
| 339 | switch ($valid) { |
| 340 | case 'errorJs': |
| 341 | $this->waitForElementPresent('css=label.error'); |
| 342 | break; |
| 343 | |
| 344 | default: |
| 345 | $this->waitForElementPresent('css=#crm-notification-container .error.ui-notify-message'); |
| 346 | $this->click('css=#crm-notification-container .error .ui-notify-cross'); |
| 347 | } |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | } |