uc_attribute.test 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. <?php
  2. /**
  3. * @file
  4. * Ubercart Attribute Tests.
  5. */
  6. /**
  7. * SimpleTests for the Ubercart Attributes API.
  8. */
  9. class UbercartAttributeTestCase extends UbercartTestHelper {
  10. public static function getInfo() {
  11. return array(
  12. 'name' => 'Attribute API',
  13. 'description' => 'Test the attribute API.',
  14. 'group' => 'Ubercart',
  15. );
  16. }
  17. /**
  18. * Overrides DrupalWebTestCase::setUp().
  19. */
  20. protected function setUp($modules = array(), $permissions = array()) {
  21. parent::setUp(array('uc_attribute'), array('administer attributes', 'administer product attributes', 'administer product options'));
  22. $this->drupalLogin($this->adminUser);
  23. }
  24. /**
  25. * Tests the basic attribute API.
  26. */
  27. public function testAttributeAPI() {
  28. // Create an attribute.
  29. $attribute = self::createAttribute();
  30. // Test retrieval.
  31. $loaded_attribute = uc_attribute_load($attribute->aid);
  32. // Check the attribute integrity.
  33. foreach (self::attributeFieldsToTest() as $field) {
  34. if ($loaded_attribute->$field != $attribute->$field) {
  35. $this->fail(t('Attribute integrity check failed.'));
  36. break;
  37. }
  38. }
  39. // Add a product.
  40. $product = $this->createProduct();
  41. // Attach the attribute to a product.
  42. uc_attribute_subject_save($attribute, 'product', $product->nid);
  43. // Confirm the database is correct.
  44. $this->assertEqual($attribute->aid, db_query("SELECT aid FROM {uc_product_attributes} WHERE nid = :nid", array(':nid' => $product->nid))->fetchField(), t('Attribute was attached to a product properly.'));
  45. $this->assertTrue(uc_attribute_subject_exists($attribute->aid, 'product', $product->nid));
  46. // Test retrieval.
  47. $loaded_attribute = uc_attribute_load($attribute->aid, $product->nid, 'product');
  48. // Check the attribute integrity.
  49. foreach (self::attributeFieldsToTest('product') as $field) {
  50. if ($loaded_attribute->$field != $attribute->$field) {
  51. $this->fail(t('Attribute integrity check failed.'));
  52. break;
  53. }
  54. }
  55. // Delete it.
  56. uc_attribute_subject_delete($attribute->aid, 'product', $product->nid);
  57. // Confirm again.
  58. $this->assertFalse(db_query("SELECT aid FROM {uc_product_attributes} WHERE nid = :nid", array(':nid' => $product->nid))->fetchField(), t('Attribute was detached from a product properly.'));
  59. $this->assertFalse(uc_attribute_subject_exists($attribute->aid, 'product', $product->nid));
  60. // Add a product class.
  61. $product_class = $this->createProductClass();
  62. // Attach the attribute to a product class.
  63. uc_attribute_subject_save($attribute, 'class', $product_class->pcid);
  64. // Confirm the database is correct.
  65. $this->assertEqual($attribute->aid, db_query("SELECT aid FROM {uc_class_attributes} WHERE pcid = :pcid", array(':pcid' => $product_class->pcid))->fetchField(), t('Attribute was attached to a product class properly.'));
  66. $this->assertTrue(uc_attribute_subject_exists($attribute->aid, 'class', $product_class->pcid));
  67. // Test retrieval.
  68. $loaded_attribute = uc_attribute_load($attribute->aid, $product_class->pcid, 'class');
  69. // Check the attribute integrity.
  70. foreach (self::attributeFieldsToTest('class') as $field) {
  71. if ($loaded_attribute->$field != $attribute->$field) {
  72. $this->fail(t('Attribute integrity check failed.'));
  73. break;
  74. }
  75. }
  76. // Delete it.
  77. uc_attribute_subject_delete($attribute->aid, 'class', $product_class->pcid);
  78. // Confirm again.
  79. $this->assertFalse(db_query("SELECT aid FROM {uc_class_attributes} WHERE pcid = :pcid", array(':pcid' => $product_class->pcid))->fetchField(), t('Attribute was detached from a product class properly.'));
  80. $this->assertFalse(uc_attribute_subject_exists($attribute->aid, 'class', $product_class->pcid));
  81. // Create a few more.
  82. for ($i = 0; $i < 5; $i++) {
  83. $a = self::createAttribute();
  84. $attributes[$a->aid] = $a;
  85. }
  86. // Add some options, organizing them by aid and oid.
  87. $attribute_aids = array_keys($attributes);
  88. $all_options = array();
  89. foreach ($attribute_aids as $aid) {
  90. for ($i = 0; $i < 3; $i++) {
  91. $option = self::createAttributeOption(array('aid' => $aid));
  92. $all_options[$option->aid][$option->oid] = $option;
  93. }
  94. }
  95. for ($i = 0; $i < 3; $i++) {
  96. $option = self::createAttributeOption(array('aid' => $aid));
  97. $all_options[$option->aid][$option->oid] = $option;
  98. }
  99. // Get the options.
  100. $attribute = uc_attribute_load($attribute->aid);
  101. // Load every attribute we got.
  102. $attributes_with_options = uc_attribute_load_multiple();
  103. // Make sure all the new options are on attributes correctly.
  104. foreach ($all_options as $aid => $options) {
  105. foreach ($options as $oid => $option) {
  106. foreach (self::attributeOptionFieldsToTest() as $field) {
  107. if ($option->$field != $attributes_with_options[$aid]->options[$oid]->$field) {
  108. $this->fail(t('Option integrity check failed.'));
  109. break;
  110. }
  111. }
  112. }
  113. }
  114. // Pick 5 keys to check at random.
  115. $aids = drupal_map_assoc(array_rand($attributes, 3));
  116. // Load the attributes back.
  117. $loaded_attributes = uc_attribute_load_multiple($aids);
  118. // Make sure we only got the attributes we asked for. No more, no less.
  119. $this->assertEqual(count($aids), count($loaded_attributes), t('Verifying attribute result.'));
  120. $this->assertEqual(count($aids), count(array_intersect_key($aids, $loaded_attributes)), t('Verifying attribute result.'));
  121. // Check the attributes' integrity.
  122. foreach ($loaded_attributes as $aid => $loaded_attribute) {
  123. foreach (self::attributeFieldsToTest() as $field) {
  124. if ($attributes[$aid]->$field != $loaded_attributes[$aid]->$field) {
  125. $this->fail(t('Attribute integrity check failed.'));
  126. break;
  127. }
  128. }
  129. }
  130. // Add the selected attributes to the product.
  131. foreach ($loaded_attributes as $loaded_attribute) {
  132. uc_attribute_subject_save($loaded_attribute, 'product', $product->nid, TRUE);
  133. }
  134. // Test loading all product attributes. (This covers uc_attribute_load_product_attributes(),
  135. // as the semantics are the same -cha0s)
  136. $loaded_product_attributes = uc_attribute_load_multiple(array(), 'product', $product->nid);
  137. // We'll get all in $loaded_attributes above, plus the original.
  138. $product_attributes = $loaded_attributes;
  139. // Make sure we only got the attributes we asked for. No more, no less.
  140. $this->assertEqual(count($loaded_product_attributes), count($product_attributes), t('Verifying attribute result.'));
  141. $this->assertEqual(count($loaded_product_attributes), count(array_intersect_key($loaded_product_attributes, $product_attributes)), t('Verifying attribute result.'));
  142. // Check the attributes' integrity.
  143. foreach ($loaded_product_attributes as $aid => $loaded_product_attribute) {
  144. foreach (self::attributeFieldsToTest('product') as $field) {
  145. if ($loaded_product_attributes[$aid]->$field != $product_attributes[$aid]->$field) {
  146. $this->fail(t('Attribute integrity check failed.'));
  147. break;
  148. }
  149. }
  150. }
  151. // Make sure all the options are on attributes correctly.
  152. foreach ($all_options as $aid => $options) {
  153. foreach ($options as $oid => $option) {
  154. if (empty($loaded_product_attributes[$aid]) || empty($loaded_product_attributes[$aid]->options[$oid])) continue;
  155. foreach (self::attributeOptionFieldsToTest() as $field) {
  156. if ($option->$field != $loaded_product_attributes[$aid]->options[$oid]->$field) {
  157. $this->fail(t('Option integrity check failed.'));
  158. break;
  159. }
  160. }
  161. }
  162. }
  163. // Add the selected attributes to the product.
  164. foreach ($loaded_attributes as $loaded_attribute) {
  165. uc_attribute_subject_save($loaded_attribute, 'class', $product_class->pcid, TRUE);
  166. }
  167. // Test loading all product attributes. (This covers uc_attribute_load_product_attributes(),
  168. // as the semantics are the same -cha0s)
  169. $loaded_class_attributes = uc_attribute_load_multiple(array(), 'class', $product_class->pcid);
  170. // We'll get all in $loaded_attributes above, plus the original.
  171. $class_attributes = $loaded_attributes;
  172. // Make sure we only got the attributes we asked for. No more, no less.
  173. $this->assertEqual(count($loaded_class_attributes), count($class_attributes), t('Verifying attribute result.'));
  174. $this->assertEqual(count($loaded_class_attributes), count(array_intersect_key($loaded_class_attributes, $class_attributes)), t('Verifying attribute result.'));
  175. // Check the attributes' integrity.
  176. foreach ($loaded_class_attributes as $aid => $loaded_class_attribute) {
  177. foreach (self::attributeFieldsToTest('class') as $field) {
  178. if ($loaded_class_attributes[$aid]->$field != $class_attributes[$aid]->$field) {
  179. $this->fail(t('Attribute integrity check failed.'));
  180. break;
  181. }
  182. }
  183. }
  184. // Make sure all the options are on attributes correctly.
  185. foreach ($all_options as $aid => $options) {
  186. foreach ($options as $oid => $option) {
  187. if (empty($loaded_class_attributes[$aid]) || empty($loaded_class_attributes[$aid]->options[$oid])) continue;
  188. foreach (self::attributeOptionFieldsToTest() as $field) {
  189. if ($option->$field != $loaded_class_attributes[$aid]->options[$oid]->$field) {
  190. $this->fail(t('Option integrity check failed.'));
  191. break;
  192. }
  193. }
  194. }
  195. }
  196. // Test deletion of base attribute.
  197. $aid = $attribute->aid;
  198. $options = $attribute->options;
  199. uc_attribute_delete($attribute->aid);
  200. $this->assertFalse(uc_attribute_load($attribute->aid), t('Attribute was deleted properly.'));
  201. // Sanity check!
  202. $this->assertFalse(db_query("SELECT aid FROM {uc_attributes} WHERE aid = :aid", array(':aid' => $attribute->aid))->fetchField(), t('Attribute was seriously deleted properly!'));
  203. // Test that options were deleted properly.
  204. foreach ($options as $option) {
  205. $this->assertFalse(db_query("SELECT oid FROM {uc_attribute_options} WHERE oid = :oid", array(':oid' => $option->oid))->fetchField(), t('Make sure options are deleted properly.'));
  206. }
  207. // Test the deletion applied to products too.
  208. $loaded_product_attributes = uc_attribute_load_multiple(array(), 'product', $product->nid);
  209. // We'll get all in $loaded_attributes above, without the original. (Which
  210. // has been deleted.)
  211. $product_attributes = $loaded_attributes;
  212. // Make sure we only got the attributes we asked for. No more, no less.
  213. $this->assertEqual(count($loaded_product_attributes), count($product_attributes), t('Verifying attribute result.'));
  214. $this->assertEqual(count($loaded_product_attributes), count(array_intersect_key($loaded_product_attributes, $product_attributes)), t('Verifying attribute result.'));
  215. // Test the deletion applied to classes too.
  216. $loaded_class_attributes = uc_attribute_load_multiple(array(), 'class', $product_class->pcid);
  217. // We'll get all in $loaded_attributes above, without the original. (Which
  218. // has been deleted.)
  219. $class_attributes = $loaded_attributes;
  220. // Make sure we only got the attributes we asked for. No more, no less.
  221. $this->assertEqual(count($loaded_class_attributes), count($class_attributes), t('Verifying attribute result.'));
  222. $this->assertEqual(count($loaded_class_attributes), count(array_intersect_key($loaded_class_attributes, $class_attributes)), t('Verifying attribute result.'));
  223. // Add some adjustments.
  224. self::createProductAdjustment(array('combination' => 'a:1:{i:1;s:1:"1";}', 'nid' => 1));
  225. self::createProductAdjustment(array('combination' => 'a:1:{i:1;s:1:"2";}', 'nid' => 1));
  226. self::createProductAdjustment(array('combination' => 'a:1:{i:1;s:1:"3";}', 'nid' => 1));
  227. self::createProductAdjustment(array('combination' => 'a:1:{i:2;s:1:"1";}', 'nid' => 2));
  228. self::createProductAdjustment(array('combination' => 'a:1:{i:3;s:1:"1";}', 'nid' => 2));
  229. self::createProductAdjustment(array('combination' => 'a:1:{i:1;s:1:"2";}', 'nid' => 3));
  230. self::createProductAdjustment(array('combination' => 'a:1:{i:1;s:1:"3";}', 'nid' => 3));
  231. self::createProductAdjustment(array('combination' => 'a:1:{i:3;s:1:"2";}', 'nid' => 3));
  232. self::createProductAdjustment(array('combination' => 'a:1:{i:3;s:1:"3";}', 'nid' => 4));
  233. // Test deletion by nid.
  234. uc_attribute_adjustments_delete(array('nid' => 1));
  235. $this->assertEqual(6, db_query("SELECT COUNT(*) FROM {uc_product_adjustments}")->fetchField());
  236. // Test deletion by aid.
  237. uc_attribute_adjustments_delete(array('aid' => 2));
  238. $this->assertEqual(5, db_query("SELECT COUNT(*) FROM {uc_product_adjustments}")->fetchField());
  239. // Test deletion by oid.
  240. uc_attribute_adjustments_delete(array('oid' => 2));
  241. $this->assertEqual(3, db_query("SELECT COUNT(*) FROM {uc_product_adjustments}")->fetchField());
  242. // Test deletion by aid and oid.
  243. uc_attribute_adjustments_delete(array('aid' => 1, 'oid' => 3));
  244. $this->assertEqual(2, db_query("SELECT COUNT(*) FROM {uc_product_adjustments}")->fetchField());
  245. }
  246. /**
  247. * Tests the "add attribute" user interface.
  248. */
  249. public function testAttributeUIAddAttribute() {
  250. $this->drupalGet('admin/store/products/attributes/add');
  251. $this->assertText(t('The name of the attribute used in administrative forms'), t('Attribute add form working.'));
  252. $edit = (array) self::createAttribute(array(), FALSE);
  253. $this->drupalPost('admin/store/products/attributes/add', $edit, t('Submit'));
  254. if ($edit['display'] != 0) {
  255. // We redirect to add options page ONLY for non-textfield attributes.
  256. $this->assertText('Options for ' . $edit['name']);
  257. $this->assertText('No options for this attribute have been added yet.');
  258. }
  259. else {
  260. // For textfield attributes we redirect to attribute list.
  261. }
  262. $this->drupalGet('admin/store/products/attributes');
  263. $this->assertRaw('<td class="active">' . $edit['name'] . '</td>', t('Verify name field.'));
  264. $this->assertRaw('<td>' . $edit['label'] . '</td>', t('Verify label field.'));
  265. $this->assertRaw('<td>' . ($edit['required'] ? t('Yes') : t('No')) . '</td>', t('Verify required field.'));
  266. $this->assertRaw('<td>' . $edit['ordering'] . '</td>', t('Verify ordering field.'));
  267. $types = _uc_attribute_display_types();
  268. $this->assertRaw('<td>' . $types[$edit['display']] . '</td>', t('Verify display field.'));
  269. $aid = db_query("SELECT aid FROM {uc_attributes} WHERE name = :name", array(':name' => $edit['name']))->fetchField();
  270. $this->assertTrue($aid, t('Attribute was created.'));
  271. $attribute = uc_attribute_load($aid);
  272. $fields_ok = TRUE;
  273. foreach ($edit as $field => $value) {
  274. if ($attribute->$field != $value) {
  275. $this->showVar($attribute);
  276. $this->showVar($edit);
  277. $fields_ok = FALSE;
  278. break;
  279. }
  280. }
  281. $this->assertTrue($fields_ok, t('Attribute created properly.'));
  282. }
  283. /**
  284. * Tests the attribute settings page.
  285. */
  286. public function testAttributeUISettings() {
  287. $product = $this->createProduct();
  288. $attribute = self::createAttribute(array(
  289. 'display' => 1,
  290. ));
  291. $option = self::createAttributeOption(array(
  292. 'aid' => $attribute->aid,
  293. 'price' => 30,
  294. ));
  295. $attribute->options[$option->oid] = $option;
  296. uc_attribute_subject_save($attribute, 'product', $product->nid, TRUE);
  297. $qty = $product->default_qty;
  298. if (!$qty) {
  299. $qty = 1;
  300. }
  301. $adjust_price = uc_currency_format($option->price * $qty);
  302. $total_price = uc_currency_format(($product->sell_price + $option->price) * $qty);
  303. $raw = array(
  304. 'none' => $option->name . '</option>',
  305. 'adjustment' => $option->name . ', +' . $adjust_price . '</option>',
  306. 'total' => $total_price . '</option>',
  307. );
  308. foreach (array('none', 'adjustment', 'total') as $type) {
  309. $edit['uc_attribute_option_price_format'] = $type;
  310. $this->drupalPost('admin/store/settings/products', $edit, t('Save configuration'));
  311. $this->drupalGet('node/' . $product->nid);
  312. $this->assertRaw($raw[$type], t('Attribute option pricing is correct.'));
  313. }
  314. }
  315. /**
  316. * Tests the "edit attribute" user interface.
  317. */
  318. public function testAttributeUIEditAttribute() {
  319. $attribute = self::createAttribute();
  320. $this->drupalGet('admin/store/products/attributes/' . $attribute->aid . '/edit');
  321. $this->assertText(t('Edit attribute: @name', array('@name' => $attribute->name)), t('Attribute edit form working.'));
  322. $edit = (array) self::createAttribute(array(), FALSE);
  323. $this->drupalPost('admin/store/products/attributes/' . $attribute->aid . '/edit', $edit, t('Submit'));
  324. $attribute = uc_attribute_load($attribute->aid);
  325. $fields_ok = TRUE;
  326. foreach ($edit as $field => $value) {
  327. if ($attribute->$field != $value) {
  328. $this->showVar($attribute);
  329. $this->showVar($edit);
  330. $fields_ok = FALSE;
  331. break;
  332. }
  333. }
  334. $this->assertTrue($fields_ok, t('Attribute edited properly.'));
  335. }
  336. /**
  337. * Tests the "delete attribute" user interface.
  338. */
  339. public function testAttributeUIDeleteAttribute() {
  340. $attribute = self::createAttribute();
  341. $this->drupalGet('admin/store/products/attributes/' . $attribute->aid . '/delete');
  342. $this->assertText(t('Are you sure you want to delete the attribute @name?', array('@name' => $attribute->name)), t('Attribute delete form working.'));
  343. $edit = (array) self::createAttribute();
  344. unset($edit['aid']);
  345. $this->drupalPost('admin/store/products/attributes/' . $attribute->aid . '/delete', array(), t('Delete'));
  346. $this->assertText(t('Product attribute deleted.'), t('Attribute deleted properly.'));
  347. }
  348. /**
  349. * Tests the attribute options user interface.
  350. */
  351. public function testAttributeUIAttributeOptions() {
  352. $attribute = self::createAttribute();
  353. $option = self::createAttributeOption(array('aid' => $attribute->aid));
  354. uc_attribute_option_save($option);
  355. $this->drupalGet('admin/store/products/attributes/' . $attribute->aid . '/options');
  356. $this->assertText(t('Options for @name', array('@name' => $attribute->name)), t('Attribute options form working.'));
  357. }
  358. /**
  359. * Tests the "add attribute option" user interface.
  360. */
  361. public function testAttributeUIAttributeOptionsAdd() {
  362. $attribute = self::createAttribute();
  363. $this->drupalGet('admin/store/products/attributes/' . $attribute->aid . '/options/add');
  364. $this->assertText(t('Options for @name', array('@name' => $attribute->name)), t('Attribute options add form working.'));
  365. $edit = (array) self::createAttributeOption(array('aid' => $attribute->aid), FALSE);
  366. unset($edit['aid']);
  367. $this->drupalPost('admin/store/products/attributes/' . $attribute->aid . '/options/add', $edit, t('Submit'));
  368. $option = db_query("SELECT * FROM {uc_attribute_options} WHERE aid = :aid", array(':aid' => $attribute->aid))->fetchObject();
  369. $fields_ok = TRUE;
  370. foreach ($edit as $field => $value) {
  371. if ($option->$field != $value) {
  372. $this->showVar($option);
  373. $this->showVar($edit);
  374. $fields_ok = FALSE;
  375. break;
  376. }
  377. }
  378. $this->assertTrue($fields_ok, t('Attribute option added successfully by form.'));
  379. }
  380. /**
  381. * Tests the "edit attribute options" user interface.
  382. */
  383. public function testAttributeUIAttributeOptionsEdit() {
  384. $attribute = self::createAttribute();
  385. $option = self::createAttributeOption(array('aid' => $attribute->aid));
  386. uc_attribute_option_save($option);
  387. $this->drupalGet('admin/store/products/attributes/' . $attribute->aid . '/options/' . $option->oid . '/edit');
  388. $this->assertText(t('Edit option: @name', array('@name' => $option->name)), t('Attribute options edit form working.'));
  389. $edit = (array) self::createAttributeOption(array('aid' => $attribute->aid), FALSE);
  390. unset($edit['aid']);
  391. $this->drupalPost('admin/store/products/attributes/' . $attribute->aid . '/options/' . $option->oid . '/edit', $edit, t('Submit'));
  392. $option = uc_attribute_option_load($option->oid);
  393. $fields_ok = TRUE;
  394. foreach ($edit as $field => $value) {
  395. if ($option->$field != $value) {
  396. $this->showVar($option);
  397. $this->showVar($edit);
  398. $fields_ok = FALSE;
  399. break;
  400. }
  401. }
  402. $this->assertTrue($fields_ok, t('Attribute option edited successfully by form.'));
  403. }
  404. /**
  405. * Tests the "delete attribute option" user interface.
  406. */
  407. public function testAttributeUIAttributeOptionsDelete() {
  408. $attribute = self::createAttribute();
  409. $option = self::createAttributeOption(array('aid' => $attribute->aid));
  410. uc_attribute_option_save($option);
  411. $this->drupalGet('admin/store/products/attributes/' . $attribute->aid . '/options/' . $option->oid . '/delete');
  412. $this->assertText(t('Are you sure you want to delete the option @name?', array('@name' => $option->name)), t('Attribute options delete form working.'));
  413. $this->drupalPost('admin/store/products/attributes/' . $attribute->aid . '/options/' . $option->oid . '/delete', array(), t('Delete'));
  414. $option = uc_attribute_option_load($option->oid);
  415. $this->assertFalse($option, t('Attribute option deleted successfully by form'));
  416. }
  417. /**
  418. * Tests the product class attribute user interface.
  419. */
  420. public function testAttributeUIClassAttributeOverview() {
  421. $class = $this->createProductClass();
  422. $attribute = self::createAttribute();
  423. $this->drupalGet('admin/store/products/classes/' . $class->pcid . '/attributes');
  424. $this->assertText(t('You must first add attributes to this class.'), t('Class attribute form working.'));
  425. uc_attribute_subject_save($attribute, 'class', $class->pcid);
  426. $this->drupalGet('admin/store/products/classes/' . $class->pcid . '/attributes');
  427. $this->assertNoText(t('You must first add attributes to this class.'), t('Class attribute form working.'));
  428. $a = (array) self::createAttribute(array(), FALSE);
  429. unset($a['name'], $a['description']);
  430. foreach ($a as $field => $value) {
  431. $edit["attributes[{$attribute->aid}][$field]"] = $value;
  432. }
  433. $this->showVar($edit);
  434. $this->drupalPost('admin/store/products/classes/' . $class->pcid . '/attributes', $edit, t('Save changes'));
  435. $attribute = uc_attribute_load($attribute->aid, $class->pcid, 'class');
  436. $fields_ok = TRUE;
  437. foreach ($a as $field => $value) {
  438. if ($attribute->$field != $value) {
  439. $this->showVar($attribute);
  440. $this->showVar($a);
  441. $fields_ok = FALSE;
  442. break;
  443. }
  444. }
  445. $this->assertTrue($fields_ok, t('Class attribute edited successfully by form.'));
  446. $edit = array();
  447. $edit["attributes[{$attribute->aid}][remove]"] = TRUE;
  448. $this->drupalPost('admin/store/products/classes/' . $class->pcid . '/attributes', $edit, t('Save changes'));
  449. $this->assertText(t('You must first add attributes to this class.'), t('Class attribute form working.'));
  450. }
  451. /**
  452. * Tests the "add product class attribute option" user interface.
  453. */
  454. public function testAttributeUIClassAttributeAdd() {
  455. $class = $this->createProductClass();
  456. $attribute = self::createAttribute();
  457. $this->drupalGet('admin/store/products/classes/' . $class->pcid . '/attributes/add');
  458. $this->assertRaw(t('@attribute </label>', array('@attribute' => $attribute->name)), t('Class attribute add form working.'));
  459. $edit['add_attributes[' . $attribute->aid . ']'] = 1;
  460. $this->drupalPost('admin/store/products/classes/' . $class->pcid . '/attributes/add', $edit, t('Add attributes'));
  461. $this->assertNoText(t('You must first add attributes to this class.'), t('Class attribute form working.'));
  462. }
  463. /**
  464. * Tests the product class attribute option user interface.
  465. */
  466. public function testAttributeUIClassAttributeOptionOverview() {
  467. $class = $this->createProductClass();
  468. $attribute = self::createAttribute();
  469. $option = self::createAttributeOption(array('aid' => $attribute->aid));
  470. uc_attribute_subject_save($attribute, 'class', $class->pcid);
  471. $this->drupalGet('admin/store/products/classes/' . $class->pcid . '/options');
  472. $this->assertRaw(t('@option </label>', array('@option' => $option->name)), t('Class attribute option form working.'));
  473. $o = (array) self::createAttributeOption(array('aid' => $attribute->aid), FALSE);
  474. unset($o['name'], $o['aid']);
  475. $o['select'] = TRUE;
  476. foreach ($o as $field => $value) {
  477. $edit["attributes[$attribute->aid][options][$option->oid][$field]"] = $value;
  478. }
  479. unset($o['select']);
  480. $edit["attributes[$attribute->aid][default]"] = $option->oid;
  481. $this->showVar($edit);
  482. $this->drupalPost('admin/store/products/classes/' . $class->pcid . '/options', $edit, t('Submit'));
  483. $this->assertText('The product class options have been saved.', t('Class attribute option saved.'));
  484. $this->showVar($option);
  485. $option = uc_attribute_subject_option_load($option->oid, 'class', $class->pcid);
  486. $fields_ok = TRUE;
  487. foreach ($o as $field => $value) {
  488. if ($option->$field != $value) {
  489. $this->showVar($option);
  490. $this->showVar($o);
  491. $fields_ok = FALSE;
  492. break;
  493. }
  494. }
  495. $this->assertTrue($fields_ok, t('Class attribute option edited successfully by form.'));
  496. }
  497. /**
  498. * Tests the "product attributes" page.
  499. */
  500. public function testAttributeUIProductAttributes() {
  501. $product = $this->createProduct();
  502. $attribute = self::createAttribute(array('display' => 1));
  503. $option = self::createAttributeOption(array('aid' => $attribute->aid));
  504. $this->drupalGet('node/' . $product->nid . '/edit/attributes');
  505. $this->assertText('You must first add attributes to this product.');
  506. $this->clickLink('Add an attribute');
  507. $this->assertText($attribute->name);
  508. $this->drupalPost(NULL, array('add_attributes[' . $attribute->aid . ']' => 1), t('Add attributes'));
  509. $this->assertText('1 attribute has been added.');
  510. $this->assertText($attribute->name, 'Attribute name found');
  511. $this->assertFieldByName('attributes[' . $attribute->aid . '][label]', $attribute->label, 'Attribute label found');
  512. $this->assertText($option->name, 'Default option name found');
  513. $this->assertText(uc_currency_format($option->price), 'Default option price found');
  514. $this->assertFieldByName('attributes[' . $attribute->aid . '][display]', $attribute->display, 'Attribute display setting found');
  515. $this->drupalGet('node/' . $product->nid . '/edit/attributes/add');
  516. $this->assertNoText($attribute->name);
  517. $this->assertText('No attributes left to add.');
  518. $edit = array('attributes[' . $attribute->aid . '][remove]' => 1);
  519. $this->drupalPost('node/' . $product->nid . '/edit/attributes', $edit, t('Save changes'));
  520. $this->assertText('You must first add attributes to this product.');
  521. }
  522. /**
  523. * Tests the "product options" page.
  524. */
  525. public function testAttributeUIProductOptions() {
  526. $product = $this->createProduct();
  527. $attribute = self::createAttribute(array('display' => 1));
  528. for ($i = 0; $i < 3; $i++) {
  529. $option = self::createAttributeOption(array('aid' => $attribute->aid));
  530. $attribute->options[$option->oid] = $option;
  531. }
  532. uc_attribute_subject_save($attribute, 'product', $product->nid, TRUE);
  533. $this->drupalGet('node/' . $product->nid . '/edit/options');
  534. $this->assertText($attribute->name, 'Attribute name found');
  535. foreach ($attribute->options as $option) {
  536. $this->assertText($option->name, 'Option name found');
  537. $this->assertFieldByName('attributes[' . $attribute->aid . '][options][' . $option->oid . '][cost]', $option->cost, 'Option cost field found');
  538. $this->assertFieldByName('attributes[' . $attribute->aid . '][options][' . $option->oid . '][price]', $option->price, 'Option price field found');
  539. $this->assertFieldByName('attributes[' . $attribute->aid . '][options][' . $option->oid . '][weight]', $option->weight, 'Option weight field found');
  540. }
  541. }
  542. /**
  543. * Tests the "product adjustments" page.
  544. */
  545. public function testAttributeUIProductAdjustments() {
  546. $product = $this->createProduct();
  547. $attribute = self::createAttribute(array('display' => 1));
  548. for ($i = 0; $i < 3; $i++) {
  549. $option = self::createAttributeOption(array('aid' => $attribute->aid));
  550. $adjustment = self::createProductAdjustment(array('combination' => serialize(array($attribute->aid => $option->oid)), 'nid' => $product->nid));
  551. $option->model = $adjustment->model;
  552. $attribute->options[$option->oid] = $option;
  553. }
  554. uc_attribute_subject_save($attribute, 'product', $product->nid, TRUE);
  555. $this->drupalGet('node/' . $product->nid . '/edit/adjustments');
  556. $this->assertText('Default product SKU: ' . $product->model, 'Default product SKU found');
  557. $this->assertRaw('<th>' . $attribute->name . '</th>', 'Attribute name found');
  558. foreach ($attribute->options as $option) {
  559. $this->assertRaw('<td>' . $option->name . '</td>', 'Option name found');
  560. $this->assertRaw($option->model, 'Option SKU found');
  561. }
  562. }
  563. /**
  564. * Tests attributes applied to a product.
  565. */
  566. public function testProductAttribute() {
  567. $product = $this->createProduct();
  568. $attribute = self::createAttribute(array('display' => 2, 'required' => TRUE));
  569. for ($i = 0; $i < 3; $i++) {
  570. $option = self::createAttributeOption(array('aid' => $attribute->aid));
  571. $adjustment = self::createProductAdjustment(array('combination' => serialize(array($attribute->aid => $option->oid)), 'nid' => $product->nid));
  572. $option->model = $adjustment->model;
  573. $attribute->options[$option->oid] = $option;
  574. }
  575. uc_attribute_subject_save($attribute, 'product', $product->nid, TRUE);
  576. // Product node display.
  577. $this->drupalGet('node/' . $product->nid);
  578. $this->assertText($attribute->label, 'Attribute label found for product');
  579. $this->assertText($attribute->description, 'Attribute description found for product');
  580. foreach ($attribute->options as $option) {
  581. $this->assertText($option->name, 'Option name found for product');
  582. $this->assertText(uc_currency_format($option->price), 'Option price adjustment found for product');
  583. }
  584. // Test required attribute.
  585. $this->drupalPost(NULL, array(), 'Add to cart');
  586. $this->assertText($attribute->label . ' field is required', 'Required attribute message found.');
  587. // Cart display.
  588. $price = uc_currency_format($product->sell_price + $option->price);
  589. $edit = array('attributes[' . $attribute->aid . ']' => $option->oid);
  590. $this->drupalPost(NULL, $edit, 'Add to cart');
  591. $this->assertText($attribute->label . ': ' . $option->name, 'Attribute and selected option found in cart');
  592. $this->assertText($price, 'Adjusted price found in cart');
  593. // Checkout display.
  594. $this->drupalPost(NULL, array(), 'Checkout');
  595. $this->assertText($attribute->label . ': ' . $option->name, 'Attribute and selected option found at checkout');
  596. $this->assertText($price, 'Adjusted price found at checkout');
  597. $this->checkout();
  598. // Admin order display.
  599. $cost = uc_currency_format($product->cost + $option->cost);
  600. $this->drupalGet('admin/store/orders/1');
  601. $this->assertText($attribute->label . ': ' . $option->name, 'Attribute and selected option found in admin order display');
  602. $this->assertText($option->model, 'Adjusted SKU found in admin order display');
  603. $this->assertText($cost, 'Adjusted cost found in admin order display');
  604. $this->assertText($price, 'Adjusted price found in admin order display');
  605. // Invoice display.
  606. $this->drupalGet('admin/store/orders/1/invoice');
  607. $this->assertText($attribute->label . ': ' . $option->name, 'Attribute and selected option found on invoice');
  608. $this->assertText('SKU: ' . $option->model, 'Adjusted SKU found on invoice');
  609. $this->assertText($price, 'Adjusted price found on invoice');
  610. }
  611. /**
  612. * Creates a product adjustment SKU.
  613. *
  614. * @param $data
  615. */
  616. public static function createProductAdjustment($data) {
  617. $adjustment = $data + array(
  618. 'model' => self::randomName(8),
  619. );
  620. db_insert('uc_product_adjustments')
  621. ->fields($adjustment)
  622. ->execute();
  623. return (object) $adjustment;
  624. }
  625. /**
  626. * Returns an array of available fields for product or class attributes.
  627. *
  628. * @param $type
  629. */
  630. protected static function attributeFieldsToTest($type = '') {
  631. $fields = array(
  632. 'aid', 'name', 'ordering', 'required', 'display', 'description', 'label',
  633. );
  634. switch ($type) {
  635. case 'product':
  636. case 'class':
  637. $info = uc_attribute_type_info($type);
  638. $fields = array_merge($fields, array($info['id']));
  639. break;
  640. }
  641. return $fields;
  642. }
  643. /**
  644. * Returns array of available fields for product or class attribute options.
  645. *
  646. * @param $type
  647. */
  648. protected static function attributeOptionFieldsToTest($type = '') {
  649. $fields = array(
  650. 'aid', 'oid', 'name', 'cost', 'price', 'weight', 'ordering',
  651. );
  652. switch ($type) {
  653. case 'product':
  654. case 'class':
  655. $info = uc_attribute_type_info($type);
  656. $fields = array_merge($fields, array($info['id']));
  657. break;
  658. }
  659. return $fields;
  660. }
  661. /**
  662. * Creates an attribute.
  663. *
  664. * @param $data
  665. * @param $save
  666. */
  667. public static function createAttribute($data = array(), $save = TRUE) {
  668. $attribute = $data + array(
  669. 'name' => DrupalWebTestCase::randomName(8),
  670. 'label' => DrupalWebTestCase::randomName(8),
  671. 'description' => DrupalWebTestCase::randomName(8),
  672. 'required' => mt_rand(0, 1) ? TRUE : FALSE,
  673. 'display' => mt_rand(0, 3),
  674. 'ordering' => mt_rand(-10, 10),
  675. );
  676. $attribute = (object) $attribute;
  677. if ($save) {
  678. uc_attribute_save($attribute);
  679. }
  680. return $attribute;
  681. }
  682. /**
  683. * Creates an attribute option.
  684. *
  685. * @param $data
  686. * @param $save
  687. */
  688. public static function createAttributeOption($data = array(), $save = TRUE) {
  689. $max_aid = db_select('uc_attributes', 'a')
  690. ->fields('a', array('aid'))
  691. ->orderBy('aid', 'DESC')
  692. ->range(0, 1)
  693. ->execute()
  694. ->fetchField();
  695. $option = $data + array(
  696. 'aid' => $max_aid,
  697. 'name' => DrupalWebTestCase::randomName(8),
  698. 'cost' => mt_rand(-500, 500),
  699. 'price' => mt_rand(-500, 500),
  700. 'weight' => mt_rand(-500, 500),
  701. 'ordering' => mt_rand(-10, 10),
  702. );
  703. $option = (object) $option;
  704. if ($save) {
  705. uc_attribute_option_save($option);
  706. }
  707. return $option;
  708. }
  709. /**
  710. * Debug helper function.
  711. *
  712. * @param $var
  713. */
  714. protected function showVar($var) {
  715. $this->pass('<pre>' . print_r($var, TRUE) . '</pre>');
  716. }
  717. }