PageRenderTime 103ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/app/protected/modules/zurmo/tests/unit/ZurmoWalkthroughBaseTest.php

https://bitbucket.org/zurmo/zurmo/
PHP | 757 lines | 592 code | 52 blank | 113 comment | 24 complexity | 46cfca050bdefd0aff126cc85b0aa000 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, GPL-2.0, LGPL-3.0, LGPL-2.1, BSD-2-Clause
  1. <?php
  2. /*********************************************************************************
  3. * Zurmo is a customer relationship management program developed by
  4. * Zurmo, Inc. Copyright (C) 2015 Zurmo Inc.
  5. *
  6. * Zurmo is free software; you can redistribute it and/or modify it under
  7. * the terms of the GNU Affero General Public License version 3 as published by the
  8. * Free Software Foundation with the addition of the following permission added
  9. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  10. * IN WHICH THE COPYRIGHT IS OWNED BY ZURMO, ZURMO DISCLAIMS THE WARRANTY
  11. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  12. *
  13. * Zurmo is distributed in the hope that it will be useful, but WITHOUT
  14. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  15. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License along with
  19. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  20. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  21. * 02110-1301 USA.
  22. *
  23. * You can contact Zurmo, Inc. with a mailing address at 27 North Wacker Drive
  24. * Suite 370 Chicago, IL 60606. or at email address contact@zurmo.com.
  25. *
  26. * The interactive user interfaces in original and modified versions
  27. * of this program must display Appropriate Legal Notices, as required under
  28. * Section 5 of the GNU Affero General Public License version 3.
  29. *
  30. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  31. * these Appropriate Legal Notices must retain the display of the Zurmo
  32. * logo and Zurmo copyright notice. If the display of the logo is not reasonably
  33. * feasible for technical reasons, the Appropriate Legal Notices must display the words
  34. * "Copyright Zurmo Inc. 2015. All rights reserved".
  35. ********************************************************************************/
  36. /**
  37. * Parent class for walkthrough documentation tests
  38. */
  39. class ZurmoWalkthroughBaseTest extends ZurmoBaseTest
  40. {
  41. private $testModelIds = array();
  42. public function setUp()
  43. {
  44. parent::setUp();
  45. Yii::app()->user->clearStates(); //reset session.
  46. Yii::app()->clientScript->reset();
  47. $_GET = null;
  48. $_REQUEST = null;
  49. $_POST = null;
  50. $_COOKIE = null;
  51. }
  52. /**
  53. * Use this method to clear the current user and login a new user for a walkthrough.
  54. */
  55. protected function logoutCurrentUserLoginNewUserAndGetByUsername($username)
  56. {
  57. //clear states does not log the user out.
  58. //todo: actually log user out and then back in.
  59. Yii::app()->user->clearStates(); //reset session.
  60. Yii::app()->language = Yii::app()->getConfigLanguageValue();
  61. Yii::app()->timeZoneHelper->setTimeZone(Yii::app()->getConfigTimeZoneValue());
  62. $user = User::getByUsername($username);
  63. //todo: actually run login?
  64. Yii::app()->user->userModel = $user;
  65. //Mimic page request to page request behavior where the php cache would be reset.
  66. RedBeanModelsCache::forgetAll(true);
  67. //todo: maybe call GeneralCache forgetAllPHPCache and also expand PermissionsCache
  68. //to have flags for php cache forgetting only.
  69. //todo: can we somehow use behavior to do these type of loads like languageHelper->load()?
  70. //this way we can utilize the same process as the normal production run of the application.
  71. Yii::app()->languageHelper->load();
  72. Yii::app()->timeZoneHelper->load();
  73. return $user;
  74. }
  75. /**
  76. * Helper method to run a controller action that is
  77. * expected not to produce an exception.
  78. */
  79. protected function runControllerWithNoExceptionsAndGetContent($route, $empty = false)
  80. {
  81. $_SERVER['REQUEST_URI'] = '/index.php';
  82. $this->startOutputBuffer();
  83. try
  84. {
  85. Yii::app()->runController($route);
  86. $content = $this->endAndGetOutputBuffer();
  87. $this->doApplicationScriptPathsAllExist();
  88. if ($empty)
  89. {
  90. $this->assertEmpty($content);
  91. }
  92. else
  93. {
  94. $this->assertNotEmpty($content);
  95. }
  96. return $content;
  97. }
  98. catch (ExitException $e)
  99. {
  100. $this->endPrintOutputBufferAndFail();
  101. }
  102. }
  103. /**
  104. * Helper method to run a controller action that is
  105. * expected produce an exit exception
  106. */
  107. protected function runControllerWithExitExceptionAndGetContent($route)
  108. {
  109. $_SERVER['REQUEST_URI'] = '/index.php';
  110. $this->startOutputBuffer();
  111. try
  112. {
  113. Yii::app()->runController($route);
  114. $this->endPrintOutputBufferAndFail();
  115. }
  116. catch (ExitException $e)
  117. {
  118. $content = $this->endAndGetOutputBuffer();
  119. $this->doApplicationScriptPathsAllExist();
  120. return $content;
  121. }
  122. }
  123. /**
  124. * Helper method to run a controller action that is
  125. * expected produce a redirect exception.
  126. */
  127. protected function runControllerWithRedirectExceptionAndGetUrl($route)
  128. {
  129. $_SERVER['REQUEST_URI'] = '/index.php';
  130. $this->startOutputBuffer();
  131. try
  132. {
  133. Yii::app()->runController($route);
  134. $this->endPrintOutputBufferAndFail();
  135. }
  136. catch (RedirectException $e)
  137. {
  138. $content = $this->endAndGetOutputBuffer();
  139. $this->doApplicationScriptPathsAllExist();
  140. $this->assertEmpty($content);
  141. return $e->getUrl();
  142. }
  143. }
  144. /**
  145. * Helper method to run a controller action that is
  146. * expected produce a redirect exception.
  147. */
  148. protected function runControllerWithRedirectExceptionAndGetContent($route, $compareUrl = null,
  149. $compareUrlContains = false)
  150. {
  151. $_SERVER['REQUEST_URI'] = '/index.php';
  152. $this->startOutputBuffer();
  153. try
  154. {
  155. Yii::app()->runController($route);
  156. $this->endPrintOutputBufferAndFail();
  157. }
  158. catch (RedirectException $e)
  159. {
  160. $content = $this->endAndGetOutputBuffer();
  161. $this->doApplicationScriptPathsAllExist();
  162. if ($compareUrl != null)
  163. {
  164. if ($compareUrlContains)
  165. {
  166. $pos = strpos($e->getUrl(), $compareUrl);
  167. if ($pos === false)
  168. {
  169. $this->fail($e->getUrl());
  170. }
  171. }
  172. else
  173. {
  174. $this->assertEquals($compareUrl, $e->getUrl());
  175. }
  176. }
  177. if (!empty($content))
  178. {
  179. echo $content;
  180. }
  181. $this->assertEmpty($content);
  182. return $content;
  183. }
  184. }
  185. /**
  186. * Helper method to run a controller action that is
  187. * expected produce a AccessDeniedSecurityException exception.
  188. */
  189. protected function runControllerWithAccessDeniedSecurityExceptionAndGetContent($route)
  190. {
  191. $_SERVER['REQUEST_URI'] = '/index.php';
  192. $this->startOutputBuffer();
  193. try
  194. {
  195. Yii::app()->runController($route);
  196. $this->endPrintOutputBufferAndFail();
  197. }
  198. catch (AccessDeniedSecurityException $e)
  199. {
  200. $content = $this->endAndGetOutputBuffer();
  201. $this->doApplicationScriptPathsAllExist();
  202. return $content;
  203. }
  204. }
  205. /**
  206. * Helper method to run a controller action that is
  207. * expected produce a NotSupported exception.
  208. */
  209. protected function runControllerWithNotSupportedExceptionAndGetContent($route)
  210. {
  211. $_SERVER['REQUEST_URI'] = '/index.php';
  212. $this->startOutputBuffer();
  213. try
  214. {
  215. Yii::app()->runController($route);
  216. $this->endPrintOutputBufferAndFail();
  217. }
  218. catch (NotSupportedException $e)
  219. {
  220. $content = $this->endAndGetOutputBuffer();
  221. $this->doApplicationScriptPathsAllExist();
  222. return $content;
  223. }
  224. }
  225. /**
  226. * Helper method to run a controller action that is
  227. * expected produce a NotFound exception.
  228. */
  229. protected function runControllerWithNotFoundExceptionAndGetContent($route)
  230. {
  231. $_SERVER['REQUEST_URI'] = '/index.php';
  232. $this->startOutputBuffer();
  233. try
  234. {
  235. Yii::app()->runController($route);
  236. $this->endPrintOutputBufferAndFail();
  237. }
  238. catch (NotFoundException $e)
  239. {
  240. $content = $this->endAndGetOutputBuffer();
  241. $this->doApplicationScriptPathsAllExist();
  242. return $content;
  243. }
  244. }
  245. protected function runControllerShouldResultInAccessFailureAndGetContent($route)
  246. {
  247. $content = $this->runControllerWithExitExceptionAndGetContent($route);
  248. $this->assertContains('You have tried to access a page you do not have access to.', $content);
  249. return $content;
  250. }
  251. protected function runControllerShouldResultInAjaxAccessFailureAndGetContent($route)
  252. {
  253. $content = $this->runControllerWithExitExceptionAndGetContent($route);
  254. $this->assertContains('failure', $content);
  255. return $content;
  256. }
  257. protected function resetGetArray()
  258. {
  259. $_GET = array();
  260. }
  261. protected function setGetArray($data)
  262. {
  263. $this->resetGetArray();
  264. foreach ($data as $key => $value)
  265. {
  266. $_GET[$key] = $value;
  267. }
  268. }
  269. protected function resetPostArray()
  270. {
  271. $_POST = array();
  272. }
  273. protected function setPostArray($data)
  274. {
  275. $this->resetPostArray();
  276. foreach ($data as $key => $value)
  277. {
  278. $_POST[$key] = $value;
  279. }
  280. // this is to get getIsPostRequest() working in CHTTPRequest
  281. $_SERVER['REQUEST_METHOD'] = 'POST';
  282. }
  283. protected static function getModelIdByModelNameAndName($modelName, $name)
  284. {
  285. $models = $modelName::getByName($name);
  286. return $models[0]->id;
  287. }
  288. protected function doApplicationScriptPathsAllExist()
  289. {
  290. foreach (Yii::app()->getClientScript()->getScriptFiles() as $scriptsPathsByPosition)
  291. {
  292. foreach ($scriptsPathsByPosition as $position => $scriptPath)
  293. {
  294. if (strpos($scriptPath, 'http') === false)
  295. {
  296. $this->assertTrue(file_exists($scriptPath), $scriptPath . 'does not exist and it should.');
  297. }
  298. }
  299. }
  300. }
  301. protected function createCheckBoxCustomFieldByModule($moduleClassName, $name)
  302. {
  303. $extraPostData = array( 'defaultValue' => '1', 'isAudited' => '1');
  304. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'CheckBox', $extraPostData, null, true);
  305. }
  306. protected function createCurrencyValueCustomFieldByModule($moduleClassName, $name)
  307. {
  308. $extraPostData = array( 'isAudited' => '1', 'isRequired' => '1');
  309. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'CurrencyValue', $extraPostData, null, true);
  310. }
  311. protected function createDateCustomFieldByModule($moduleClassName, $name)
  312. {
  313. $extraPostData = array( 'defaultValueCalculationType' => '', 'isAudited' => '1', 'isRequired' => '1');
  314. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'Date', $extraPostData, null, true);
  315. }
  316. protected function createDateNotRequiredCustomFieldByModule($moduleClassName, $name)
  317. {
  318. $extraPostData = array( 'defaultValueCalculationType' => '', 'isAudited' => '1');
  319. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'Date', $extraPostData, null, true);
  320. }
  321. protected function createDateTimeCustomFieldByModule($moduleClassName, $name)
  322. {
  323. $extraPostData = array( 'defaultValueCalculationType' => '', 'isAudited' => '1', 'isRequired' => '1');
  324. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'DateTime', $extraPostData, null, true);
  325. }
  326. protected function createDecimalCustomFieldByModule($moduleClassName, $name)
  327. {
  328. $extraPostData = array( 'defaultValue' => '123', 'isAudited' => '1', 'isRequired' => '1',
  329. 'maxLength' => '18', 'precisionLength' => '2');
  330. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'Decimal', $extraPostData, null, true);
  331. }
  332. protected function createIntegerCustomFieldByModule($moduleClassName, $name)
  333. {
  334. $extraPostData = array( 'defaultValue' => '123', 'isAudited' => '1', 'isRequired' => '1',
  335. 'maxLength' => '11', 'minValue' => '2', 'maxValue' => '400');
  336. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'Integer', $extraPostData, null, true);
  337. }
  338. protected function createPhoneCustomFieldByModule($moduleClassName, $name)
  339. {
  340. $extraPostData = array( 'defaultValue' => '5423', 'isAudited' => '1', 'isRequired' => '1',
  341. 'maxLength' => '20');
  342. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'Phone', $extraPostData, null, true);
  343. }
  344. protected function createTextCustomFieldByModule($moduleClassName, $name)
  345. {
  346. $extraPostData = array( 'defaultValue' => 'aText', 'isAudited' => '1', 'isRequired' => '1',
  347. 'maxLength' => '255');
  348. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'Text', $extraPostData, null, true);
  349. }
  350. protected function createTextAreaCustomFieldByModule($moduleClassName, $name)
  351. {
  352. $extraPostData = array( 'defaultValue' => 'aTextDesc', 'isAudited' => '1', 'isRequired' => '1');
  353. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'TextArea', $extraPostData, null, true);
  354. }
  355. protected function createUrlCustomFieldByModule($moduleClassName, $name)
  356. {
  357. $extraPostData = array( 'defaultValue' => 'http://www.zurmo.com', 'isAudited' => '1', 'isRequired' => '1',
  358. 'maxLength' => '200');
  359. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'Url', $extraPostData, null, true);
  360. }
  361. protected function createDropDownCustomFieldByModule($moduleClassName, $name)
  362. {
  363. $extraPostData = array( 'defaultValueOrder' => '2',
  364. 'isAudited' => '1',
  365. 'isRequired' => '1',
  366. 'customFieldDataData' => array(
  367. 'a', 'b', 'c'
  368. ),
  369. 'customFieldDataLabels' => array(
  370. 'fr' => array('aFr', 'bFr', 'cFr'),
  371. 'de' => array('aDe', 'bDe', 'cDe'),
  372. )
  373. );
  374. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'DropDown', $extraPostData, null, true);
  375. }
  376. protected function createDependentDropDownCustomFieldByModule($moduleClassName, $name)
  377. {
  378. $customFieldDataData = array('countrylist' => array('aaaa', 'bbbb'),
  379. 'statelist' => array('aaa1', 'aaa2', 'bbb1', 'bbb2'),
  380. 'citylist' => array('aa1', 'ab1', 'aa2', 'ab2', 'ba1', 'bb1', 'ba2', 'bb2')
  381. );
  382. $customFieldDataLabelsFr = array('countrylist' => array('aaaa Fr', 'bbbb Fr'),
  383. 'statelist' => array('aaa1 Fr', 'aaa2 Fr', 'bbb1 Fr', 'bbb2 Fr'),
  384. 'citylist' => array('aa1 Fr', 'ab1 Fr', 'aa2 Fr', 'ab2 Fr', 'ba1 Fr', 'bb1 Fr', 'ba2 Fr', 'bb2 Fr')
  385. );
  386. $customFieldDataLabelsDe = array('countrylist' => array('aaaa De', 'bbbb De'),
  387. 'statelist' => array('aaa1 De', 'aaa2 De', 'bbb1 De', 'bbb2 De'),
  388. 'citylist' => array('aa1 De', 'ab1 De', 'aa2 De', 'ab2 De', 'ba1 De', 'bb1 De', 'ba2 De', 'bb2 De')
  389. );
  390. $extraPostData = array(
  391. 'defaultValueOrder' => '1',
  392. 'isAudited' => '1',
  393. 'isRequired' => '0',
  394. 'customFieldDataData' => $customFieldDataData[$name],
  395. 'customFieldDataLabels' => array(
  396. 'fr' => $customFieldDataLabelsFr[$name],
  397. 'de' => $customFieldDataLabelsDe[$name],
  398. )
  399. );
  400. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'DropDown', $extraPostData, null, true);
  401. }
  402. protected function createRadioDropDownCustomFieldByModule($moduleClassName, $name)
  403. {
  404. $extraPostData = array( 'defaultValueOrder' => '2',
  405. 'isAudited' => '1',
  406. 'isRequired' => '1',
  407. 'customFieldDataData' => array(
  408. 'd', 'e', 'f'
  409. ));
  410. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'RadioDropDown', $extraPostData, null, true);
  411. }
  412. protected function createMultiSelectDropDownCustomFieldByModule($moduleClassName, $name)
  413. {
  414. $extraPostData = array( 'defaultValueOrder' => '1',
  415. 'isAudited' => '1',
  416. 'isRequired' => '1',
  417. 'customFieldDataData' => array(
  418. 'ff', 'gg', 'hh', 'rr'
  419. ));
  420. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'MultiSelectDropDown', $extraPostData, null, true);
  421. }
  422. protected function createTagCloudCustomFieldByModule($moduleClassName, $name)
  423. {
  424. $extraPostData = array( 'defaultValueOrder' => '1',
  425. 'isAudited' => '1',
  426. 'isRequired' => '1',
  427. 'customFieldDataData' => array('reading', 'writing', 'surfing', 'gardening'),
  428. 'customFieldDataLabels' => array(
  429. 'fr' => array('reading fr', 'writing fr', 'surfing fr', 'gardening fr'),
  430. 'de' => array('reading de', 'writing de', 'surfing de', 'gardening de'),
  431. ));
  432. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'TagCloud', $extraPostData, null, true);
  433. }
  434. protected function createCalculatedNumberCustomFieldByModule($moduleClassName, $name)
  435. {
  436. $formulaForModule = array('AccountsModule' => 'employees + annualRevenue',
  437. 'ContactsModule' => 'decimalCstm + integerCstm',
  438. 'MeetingsModule' => 'decimalCstm - integerCstm',
  439. 'NotesModule' => 'decimalCstm + integerCstm',
  440. 'OpportunitiesModule' => 'decimalCstm * integerCstm',
  441. 'TasksModule' => 'decimalCstm * integerCstm',
  442. 'ProductTemplatesModule' => 'decimalCstm * integerCstm',
  443. 'ProductsModule' => 'decimalCstm * integerCstm',
  444. 'ProjectsModule' => 'decimalCstm * integerCstm');
  445. $extraPostData = array('formula' => $formulaForModule[$moduleClassName]);
  446. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'CalculatedNumber', $extraPostData, null, true);
  447. }
  448. protected function createDropDownDependencyCustomFieldByModule($moduleClassName, $name)
  449. {
  450. $mappingData = array(
  451. array('attributeName' => 'countrylistCstm'),
  452. array('attributeName' => 'statelistCstm',
  453. 'valuesToParentValues' => array('aaa1' => 'aaaa',
  454. 'aaa2' => 'aaaa',
  455. 'bbb1' => 'bbbb',
  456. 'bbb2' => 'bbbb'
  457. )
  458. ),
  459. array('attributeName' => 'citylistCstm',
  460. 'valuesToParentValues' => array('aa1' => 'aaa1',
  461. 'ab1' => 'aaa1',
  462. 'aa2' => 'aaa2',
  463. 'ab2' => 'aaa2',
  464. 'ba1' => 'bbb1',
  465. 'bb1' => 'bbb1',
  466. 'ba2' => 'bbb2',
  467. 'bb2' => 'bbb2',
  468. )
  469. ),
  470. array('attributeName' => '')
  471. );
  472. $extraPostData = array('mappingData' => $mappingData);
  473. $this->createCustomAttributeWalkthroughSequence($moduleClassName, $name, 'DropDownDependency', $extraPostData, null, true);
  474. }
  475. protected function createModuleEditBadValidationPostData()
  476. {
  477. return array('singularModuleLabels' =>
  478. array('de' => '', 'it' => 'forget everything but this', 'es' => '', 'en' => '', 'fr' => ''),
  479. 'pluralModuleLabels' =>
  480. array('de' => '', 'it' => '', 'es' => '', 'en' => '', 'fr' => '')
  481. );
  482. }
  483. protected function createModuleEditGoodValidationPostData($singularName)
  484. {
  485. assert('strtolower($singularName) == $singularName'); // Not Coding Standard
  486. $pluralName = $singularName .'s';
  487. return array('singularModuleLabels' =>
  488. array('de' => $singularName, 'it' => $singularName, 'es' => $singularName,
  489. 'en' => $singularName, 'fr' => $singularName),
  490. 'pluralModuleLabels' =>
  491. array( 'de' => $pluralName, 'it' => $pluralName, 'es' => $pluralName,
  492. 'en' => $pluralName, 'fr' => $pluralName)
  493. );
  494. }
  495. protected function createAttributeLabelBadValidationPostData()
  496. {
  497. return array('de' => '', 'it' => 'forget everything but this', 'es' => '', 'en' => '', 'fr' => ''
  498. );
  499. }
  500. protected function createAttributeLabelGoodValidationPostData($name)
  501. {
  502. assert('strtolower($name) == $name'); // Not Coding Standard
  503. return array('de' => $name . ' de', 'it' => $name . ' it', 'es' => $name . ' es',
  504. 'en' => $name . ' en', 'fr' => $name . ' fr'
  505. );
  506. }
  507. protected function createCustomAttributeWalkthroughSequence($moduleClassName,
  508. $name,
  509. $attributeTypeName,
  510. $extraPostData,
  511. $attributeName = null,
  512. $isCustomField = false)
  513. {
  514. assert('$name[0] == strtolower($name[0])'); // Not Coding Standard
  515. assert('is_array($extraPostData)'); // Not Coding Standard
  516. $formName = $attributeTypeName . 'AttributeForm';
  517. $this->setGetArray(array( 'moduleClassName' => $moduleClassName,
  518. 'attributeTypeName' => $attributeTypeName,
  519. 'attributeName' => $attributeName));
  520. $this->resetPostArray();
  521. //Now test going to the user interface edit view.
  522. $content = $this->runControllerWithNoExceptionsAndGetContent('designer/default/attributeEdit');
  523. //Now validate save with failed validation.
  524. $this->setPostArray(array( 'ajax' => 'edit-form',
  525. $formName => array_merge(array(
  526. 'attributeLabels' => $this->createAttributeLabelBadValidationPostData($name),
  527. 'attributeName' => $name,
  528. ), $extraPostData)));
  529. $content = $this->runControllerWithExitExceptionAndGetContent('designer/default/attributeEdit');
  530. $this->assertTrue(strlen($content) > 50); //approximate, but should definetely be larger than 50.
  531. //Now validate save with successful validation.
  532. $this->setPostArray(array( 'ajax' => 'edit-form',
  533. $formName => array_merge(array(
  534. 'attributeLabels' => $this->createAttributeLabelGoodValidationPostData($name),
  535. 'attributeName' => $name,
  536. ), $extraPostData)));
  537. $content = $this->runControllerWithExitExceptionAndGetContent('designer/default/attributeEdit');
  538. $this->assertEquals('[]', $content);
  539. //Now save successfully.
  540. $this->setPostArray(array( 'save' => 'Save',
  541. $formName => array_merge(array(
  542. 'attributeLabels' => $this->createAttributeLabelGoodValidationPostData($name),
  543. 'attributeName' => $name,
  544. ), $extraPostData)));
  545. $this->runControllerWithRedirectExceptionAndGetContent('designer/default/attributeEdit');
  546. //Now confirm everything did in fact save correctly.
  547. RedBeanModel::forgetAll();
  548. $modelClassName = $moduleClassName::getPrimaryModelName();
  549. $newModel = new $modelClassName(false);
  550. $compareData = array(
  551. 'de' => $name . ' de',
  552. 'it' => $name . ' it',
  553. 'es' => $name . ' es',
  554. 'en' => $name . ' en',
  555. 'fr' => $name . ' fr',
  556. );
  557. if ($isCustomField)
  558. {
  559. $name = $name . 'Cstm';
  560. }
  561. if ($attributeTypeName != "CalculatedNumber" && $attributeTypeName != "DropDownDependency")
  562. {
  563. $this->assertEquals(
  564. $compareData, $newModel->getAttributeLabelsForAllActiveLanguagesByAttributeName($name));
  565. }
  566. if ($attributeTypeName != "CalculatedNumber" && $attributeTypeName != "DropDownDependency")
  567. {
  568. //Now test going to the user interface edit view for the existing attribute.
  569. $this->setGetArray(array( 'moduleClassName' => $moduleClassName,
  570. 'attributeTypeName' => $attributeTypeName,
  571. 'attributeName' => $name));
  572. // if we don't do this attributeName from POST will override and result in duplicate columns.
  573. // Frontend also doesn't send attributeName in POST on edit.
  574. unset($_POST[$formName]['attributeName']);
  575. $content = $this->runControllerWithRedirectExceptionAndGetContent('designer/default/attributeEdit');
  576. }
  577. }
  578. private function buildAttributesArrayFromPostArray($postArray)
  579. {
  580. $testAttributes = array();
  581. foreach ($postArray as $moduleClass => $values)
  582. {
  583. foreach ($values as $attribute => $value)
  584. {
  585. if (is_array($value))
  586. {
  587. $testAttributes[$attribute] = $this->buildAttributesArrayFromPostArray(array('dummy' => $value));
  588. }
  589. else
  590. {
  591. $testAttributes[] = $attribute;
  592. }
  593. }
  594. }
  595. return $testAttributes;
  596. }
  597. /**
  598. * Uses postArray to check response field values.
  599. * @param $model
  600. * @param $postArray
  601. * @param null $linkClass
  602. * @return bool
  603. */
  604. protected function checkCopyActionResponseAttributeValuesFromPostArray($model, $postArray, $linkClass = null,
  605. $controllerId = null)
  606. {
  607. return $this->checkCopyActionResponseAttributeValues(
  608. $model,
  609. $this->buildAttributesArrayFromPostArray($postArray),
  610. $linkClass,
  611. $controllerId
  612. );
  613. }
  614. /**
  615. * Test if form fields have values from record.
  616. * It supports selects, plain text fields and textareas.
  617. * @param $model
  618. * @param $testAttributes
  619. * @param null $linkClass
  620. * @param null $controllerId
  621. * @return bool
  622. */
  623. protected function checkCopyActionResponseAttributeValues($model, $testAttributes, $linkClass = null, $controllerId = null)
  624. {
  625. $moduleClassName = $model::getModuleClassName();
  626. if ($controllerId == null)
  627. {
  628. $controllerId = $moduleClassName::getDirectoryName();
  629. }
  630. $this->setGetArray(array('id' => $model->id));
  631. $this->resetPostArray();
  632. $response = $this->runControllerWithNoExceptionsAndGetContent($controllerId . '/default/copy');
  633. return $this->checkResponseAgainstAttributeArray($response, $model, get_class($model), $testAttributes, $linkClass);
  634. }
  635. private function checkResponseAgainstAttributeArray($response, $model, $class, $testAttributes, $linkClass = null)
  636. {
  637. $attributesValid = true;
  638. $matchRulesBase = array();
  639. $matchRulesBase[] = '/id="%testAttribute%".*?>%value%<\/t/';
  640. $matchRulesBase[] = '/id="%testAttribute%".*?value="%value%"/';
  641. $matchRulesBase[] = '/id="%testAttribute%">.*?<option value="%value%" selected="selected"/s';
  642. foreach ($testAttributes as $relation => $testAttribute)
  643. {
  644. if (is_array($testAttribute))
  645. {
  646. $attributesValid = $attributesValid && $this->checkResponseAgainstAttributeArray($response, $model->{$relation}, $class . '_' . $relation, $testAttribute, $linkClass);
  647. }
  648. else
  649. {
  650. $matchResult = false;
  651. $matchRules = str_replace(
  652. array('%testAttribute%', '%value%'),
  653. array($class . '_' . $testAttribute, str_replace('/', '\/', $model->{$testAttribute})),
  654. $matchRulesBase
  655. );
  656. foreach ($matchRules as $matchRule)
  657. {
  658. $matchResult = $matchResult || preg_match($matchRule, $response);
  659. }
  660. $this->assertTrue($matchResult, $class . '_' . $testAttribute . '==' . $model->{$testAttribute});
  661. $attributesValid = $attributesValid && $matchResult;
  662. }
  663. }
  664. return (bool)$attributesValid;
  665. }
  666. /**
  667. * Updates the model with values from post array.
  668. *
  669. * @param OwnedSecurableItem $model Updated model
  670. * @param array $postArray Array of post values
  671. */
  672. protected function updateModelValuesFromPostArray($model, $postArray)
  673. {
  674. foreach ($postArray as $moduleClass => $attributeValues)
  675. {
  676. $this->assertInstanceOf($moduleClass, $model);
  677. $model->setAttributes($attributeValues);
  678. }
  679. }
  680. /**
  681. * Checks if the model has values from post array.
  682. *
  683. * @param OwnedSecurableItem $model Updated model
  684. * @param array $postArray Array of post values
  685. */
  686. protected function assertModelHasValuesFromPostArray($model, $postArray)
  687. {
  688. foreach ($postArray as $moduleClass => $attributeValues)
  689. {
  690. $this->assertInstanceOf($moduleClass, $model);
  691. foreach ($attributeValues as $attribute => $attributeValue)
  692. {
  693. if (is_array($attributeValue))
  694. {
  695. $this->assertModelHasValuesFromPostArray($model->{$attribute}, array(get_class($model->{$attribute}) => $attributeValue));
  696. }
  697. else
  698. {
  699. $this->assertEquals($attributeValue, $model->{$attribute});
  700. }
  701. }
  702. }
  703. }
  704. }
  705. ?>