uc_cart.test 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. <?php
  2. /**
  3. * @file
  4. * Shopping cart and checkout tests.
  5. */
  6. /**
  7. * Tests the cart and checkout functionality.
  8. */
  9. class UbercartCartCheckoutTestCase extends UbercartTestHelper {
  10. public static function getInfo() {
  11. return array(
  12. 'name' => 'Cart and checkout',
  13. 'description' => 'Ensures the cart and checkout process is functioning for both anonymous and authenticated users.',
  14. 'group' => 'Ubercart',
  15. );
  16. }
  17. /**
  18. * Overrides DrupalWebTestCase::setUp().
  19. */
  20. protected function setUp($modules = array(), $permissions = array()) {
  21. $modules = array('uc_payment', 'uc_payment_pack', 'uc_roles');
  22. $permissions = array('administer permissions');
  23. parent::setUp($modules, $permissions);
  24. }
  25. /**
  26. * Creates a new order.
  27. */
  28. protected function createOrder($fields = array()) {
  29. $order = uc_order_new();
  30. foreach ($fields as $key => $value) {
  31. $order->$key = $value;
  32. }
  33. if (empty($order->primary_email)) {
  34. $order->primary_email = $this->randomString() . '@example.org';
  35. }
  36. if (!isset($fields['products'])) {
  37. $item = clone $this->product;
  38. $item->qty = 1;
  39. $item->price = $item->sell_price;
  40. $item->data = array();
  41. $order->products = array($item);
  42. }
  43. $order->order_total = uc_order_get_total($order, TRUE);
  44. $order->line_items = uc_order_load_line_items($order, TRUE);
  45. uc_order_save($order);
  46. return $order;
  47. }
  48. /**
  49. * Tests cart API.
  50. */
  51. public function testCartApi() {
  52. // Test the empty cart.
  53. $items = uc_cart_get_contents();
  54. $this->assertEqual($items, array(), 'Cart is an empty array.');
  55. // Add an item to the cart.
  56. uc_cart_add_item($this->product->nid);
  57. $items = uc_cart_get_contents();
  58. $this->assertEqual(count($items), 1, 'Cart contains one item.');
  59. $item = reset($items);
  60. $this->assertEqual($item->nid, $this->product->nid, 'Cart item nid is correct.');
  61. $this->assertEqual($item->qty, 1, 'Cart item quantity is correct.');
  62. // Add more of the same item.
  63. $qty = mt_rand(1, 100);
  64. uc_cart_add_item($this->product->nid, $qty);
  65. $items = uc_cart_get_contents();
  66. $this->assertEqual(count($items), 1, 'Updated cart contains one item.');
  67. $item = reset($items);
  68. $this->assertEqual($item->qty, $qty + 1, 'Updated cart item quantity is correct.');
  69. // Set the quantity and data.
  70. $qty = mt_rand(1, 100);
  71. $item->qty = $qty;
  72. $item->data['updated'] = TRUE;
  73. uc_cart_update_item($item);
  74. $items = uc_cart_get_contents();
  75. $item = reset($items);
  76. $this->assertEqual($item->qty, $qty, 'Set cart item quantity is correct.');
  77. $this->assertTrue($item->data['updated'], 'Set cart item data is correct.');
  78. // Add an item with different data to the cart.
  79. uc_cart_add_item($this->product->nid, 1, array('test' => TRUE));
  80. $items = uc_cart_get_contents();
  81. $this->assertEqual(count($items), 2, 'Updated cart contains two items.');
  82. // Remove the items.
  83. foreach ($items as $item) {
  84. uc_cart_remove_item($item->nid, NULL, $item->data);
  85. }
  86. // @todo Remove the need for this.
  87. uc_cart_get_contents(NULL, 'rebuild');
  88. $items = uc_cart_get_contents();
  89. $this->assertEqual(count($items), 0, 'Cart is empty after removal.');
  90. // Empty the cart.
  91. uc_cart_add_item($this->product->nid);
  92. uc_cart_empty();
  93. $items = uc_cart_get_contents();
  94. $this->assertEqual($items, array(), 'Cart is emptied correctly.');
  95. }
  96. /**
  97. * Tests basic cart functionality.
  98. */
  99. public function testCart() {
  100. module_enable(array('uc_cart_entity_test'));
  101. // Test the empty cart.
  102. $this->drupalGet('cart');
  103. $this->assertText('There are no products in your shopping cart.');
  104. // Add an item to the cart.
  105. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  106. $this->assertText($this->product->title . ' added to your shopping cart.');
  107. $this->assertText('hook_uc_cart_item_insert fired');
  108. // Test the cart page.
  109. $this->drupalGet('cart');
  110. $this->assertText($this->product->title, t('The product is in the cart.'));
  111. $this->assertFieldByName('items[0][qty]', 1, t('The product quantity is 1.'));
  112. // Add the item again.
  113. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  114. $this->assertText('Your item(s) have been updated.');
  115. $this->assertText('hook_uc_cart_item_update fired');
  116. // Test the cart page again.
  117. $this->drupalGet('cart');
  118. $this->assertFieldByName('items[0][qty]', 2, t('The product quantity is 2.'));
  119. // Update the quantity.
  120. $qty = mt_rand(3, 100);
  121. $this->drupalPost('cart', array('items[0][qty]' => $qty), t('Update cart'));
  122. $this->assertText('Your cart has been updated.');
  123. $this->assertFieldByName('items[0][qty]', $qty, t('The product quantity was updated.'));
  124. $this->assertText('hook_uc_cart_item_update fired');
  125. // Update the quantity to zero.
  126. $this->drupalPost('cart', array('items[0][qty]' => 0), t('Update cart'));
  127. $this->assertText('Your cart has been updated.');
  128. $this->assertText('There are no products in your shopping cart.');
  129. $this->assertText('hook_uc_cart_item_delete fired');
  130. // Test the remove item button.
  131. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  132. $this->drupalPost('cart', array(), t('Remove'));
  133. $this->assertText($this->product->title . ' removed from your shopping cart.');
  134. $this->assertText('There are no products in your shopping cart.');
  135. $this->assertText('hook_uc_cart_item_delete fired');
  136. }
  137. /**
  138. * Tests that anonymous cart is merged into authenticated cart upon login.
  139. */
  140. public function testCartMerge() {
  141. // Add an item to the cart as an anonymous user.
  142. $this->drupalLogin($this->customer);
  143. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  144. $this->assertText($this->product->title . ' added to your shopping cart.');
  145. $this->drupalLogout();
  146. // Add an item to the cart as an anonymous user.
  147. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  148. $this->assertText($this->product->title . ' added to your shopping cart.');
  149. // Log in and check the items are merged.
  150. $this->drupalLogin($this->customer);
  151. $this->drupalGet('cart');
  152. $this->assertText($this->product->title, t('The product remains in the cart after logging in.'));
  153. $this->assertFieldByName('items[0][qty]', 2, t('The product quantity is 2.'));
  154. }
  155. /**
  156. * Tests that cart automatically removes products that have been deleted.
  157. */
  158. public function testDeletedCartItem() {
  159. // Add a product to the cart, then delete the node.
  160. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  161. node_delete($this->product->nid);
  162. // Test that the cart is empty.
  163. $this->drupalGet('cart');
  164. $this->assertText('There are no products in your shopping cart.');
  165. $this->assertEqual(uc_cart_get_total_qty(), 0, 'There are no items in the cart.');
  166. }
  167. /**
  168. * Tests Rule integration for uc_cart_maximum_product_qty reaction rule.
  169. */
  170. public function testMaximumQuantityRule() {
  171. // Enable the example maximum quantity rule.
  172. $rule = rules_config_load('uc_cart_maximum_product_qty');
  173. $rule->active = TRUE;
  174. $rule->save();
  175. // Try to add more items than allowed to the cart.
  176. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  177. $this->drupalPost('cart', array('items[0][qty]' => 11), t('Update cart'));
  178. // Test the restriction was applied.
  179. $this->assertText('You are only allowed to order a maximum of 10 of ' . $this->product->title . '.');
  180. $this->assertFieldByName('items[0][qty]', 10);
  181. }
  182. /**
  183. * Tests the checkout process.
  184. */
  185. public function testCheckout() {
  186. // Allow customer to specify username and password,
  187. // but don't log in after checkout.
  188. $settings = array(
  189. 'uc_cart_new_account_name' => TRUE,
  190. 'uc_cart_new_account_password' => TRUE,
  191. 'uc_new_customer_login' => FALSE,
  192. );
  193. $this->drupalLogin($this->adminUser);
  194. $this->drupalPost('admin/store/settings/checkout', $settings, t('Save configuration'));
  195. $this->drupalLogout();
  196. $new_user = new stdClass();
  197. $new_user->name = $this->randomName(20);
  198. $new_user->pass_raw = $this->randomName(20);
  199. // Test as anonymous user.
  200. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  201. $this->checkout(array(
  202. 'panes[customer][new_account][name]' => $new_user->name,
  203. 'panes[customer][new_account][pass]' => $new_user->pass_raw,
  204. 'panes[customer][new_account][pass_confirm]' => $new_user->pass_raw,
  205. ));
  206. $this->assertRaw('Your order is complete!');
  207. $this->assertText($new_user->name, 'Username is shown on screen.');
  208. $this->assertNoText($new_user->pass_raw, 'Password is not shown on screen.');
  209. // Check that cart is now empty.
  210. $this->drupalGet('cart');
  211. $this->assertText('There are no products in your shopping cart.');
  212. // Test new account email.
  213. $mail = $this->drupalGetMails(array('id' => 'user_register_no_approval_required'));
  214. $mail = array_pop($mail);
  215. $this->assertTrue(strpos($mail['body'], $new_user->name) !== FALSE, 'Mail body contains username.');
  216. // Test invoice email.
  217. $mail = $this->drupalGetMails(array('subject' => 'Your Order at Ubercart'));
  218. $mail = array_pop($mail);
  219. $this->assertTrue(strpos($mail['body'], $new_user->name) !== FALSE, 'Invoice body contains username.');
  220. $this->assertFalse(strpos($mail['body'], $new_user->pass_raw) !== FALSE, 'Mail body does not contain password.');
  221. // Check that the password works.
  222. $this->drupalLogout();
  223. $this->drupalLogin($new_user);
  224. // Test again as authenticated user.
  225. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  226. $this->checkout();
  227. $this->assertRaw('Your order is complete!');
  228. $this->assertRaw('While logged in');
  229. // Test again with generated username and password.
  230. $this->drupalLogout();
  231. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  232. $this->checkout();
  233. $this->assertRaw('Your order is complete!');
  234. // Test new account email.
  235. $mail = $this->drupalGetMails(array('id' => 'user_register_no_approval_required'));
  236. $mail = array_pop($mail);
  237. $new_user = new stdClass();
  238. $new_user->name = $mail['params']['account']->name;
  239. $new_user->pass_raw = $mail['params']['account']->password;
  240. $this->assertTrue(!empty($new_user->name), 'New username is not empty.');
  241. $this->assertTrue(!empty($new_user->pass_raw), 'New password is not empty.');
  242. $this->assertTrue(strpos($mail['body'], $new_user->name) !== FALSE, 'Mail body contains username.');
  243. // Test invoice email.
  244. $mail = $this->drupalGetMails(array('subject' => 'Your Order at Ubercart'));
  245. $mail = array_pop($mail);
  246. $this->assertTrue(strpos($mail['body'], $new_user->name) !== FALSE, 'Invoice body contains username.');
  247. $this->assertTrue(strpos($mail['body'], $new_user->pass_raw) !== FALSE, 'Invoice body contains password.');
  248. // We can check the password now we know it.
  249. $this->assertText($new_user->name, 'Username is shown on screen.');
  250. $this->assertText($new_user->pass_raw, 'Password is shown on screen.');
  251. // Check that the password works.
  252. $this->drupalLogout();
  253. $this->drupalLogin($new_user);
  254. // Test again with an existing email address.
  255. $this->drupalLogout();
  256. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  257. $this->checkout(array('panes[customer][primary_email]' => $this->customer->mail));
  258. $this->assertRaw('Your order is complete!');
  259. $this->assertRaw('order has been attached to the account we found');
  260. }
  261. /**
  262. * Tests generating a new account at checkout.
  263. */
  264. public function testCheckoutNewUsername() {
  265. // Configure the checkout for this test.
  266. $this->drupalLogin($this->adminUser);
  267. $settings = array(
  268. // Allow customer to specify username.
  269. 'uc_cart_new_account_name' => TRUE,
  270. // Disable address panes.
  271. 'uc_pane_delivery_enabled' => FALSE,
  272. 'uc_pane_billing_enabled' => FALSE,
  273. );
  274. $this->drupalPost('admin/store/settings/checkout/panes', $settings, t('Save configuration'));
  275. $this->drupalLogout();
  276. // Test with an account that already exists.
  277. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  278. $edit = array(
  279. 'panes[customer][primary_email]' => $this->randomName(8) . '@example.com',
  280. 'panes[customer][new_account][name]' => $this->adminUser->name,
  281. );
  282. $this->drupalPost('cart/checkout', $edit, 'Review order');
  283. $this->assertText('The username ' . $this->adminUser->name . ' is already taken.');
  284. // Let the account be automatically created instead.
  285. $edit = array(
  286. 'panes[customer][primary_email]' => $this->randomName(8) . '@example.com',
  287. 'panes[customer][new_account][name]' => '',
  288. );
  289. $this->drupalPost('cart/checkout', $edit, 'Review order');
  290. $this->drupalPost(NULL, array(), 'Submit order');
  291. $this->assertText('Your order is complete!');
  292. $this->assertText('A new account has been created');
  293. }
  294. /**
  295. * Tests blocked user checkout.
  296. */
  297. public function testCheckoutBlockedUser() {
  298. // Block user after checkout.
  299. $settings = array(
  300. 'uc_new_customer_status_active' => FALSE,
  301. );
  302. $this->drupalLogin($this->adminUser);
  303. $this->drupalPost('admin/store/settings/checkout', $settings, t('Save configuration'));
  304. $this->drupalLogout();
  305. // Test as anonymous user.
  306. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  307. $this->checkout();
  308. $this->assertRaw('Your order is complete!');
  309. // Test new account email.
  310. $mail = $this->drupalGetMails(array('id' => 'user_register_pending_approval'));
  311. $this->assertTrue(!empty($mail), 'Blocked user email found.');
  312. $mail = $this->drupalGetMails(array('id' => 'user_register_no_approval_required'));
  313. $this->assertTrue(empty($mail), 'No unblocked user email found.');
  314. }
  315. /**
  316. * Tests logging in the customer after checkout.
  317. */
  318. public function testCheckoutLogin() {
  319. // Log in after checkout.
  320. variable_set('uc_new_customer_login', TRUE);
  321. // Test checkout.
  322. $this->drupalGet('node/' . $this->product->nid);
  323. $this->drupalPost(NULL, array(), t('Add to cart'));
  324. $this->assertNotNull($this->session_id, 'Session ID is set.');
  325. $session_id = $this->session_id;
  326. $this->checkout();
  327. $this->assertRaw('Your order is complete!');
  328. $this->assertRaw('you are already logged in');
  329. // Confirm login.
  330. $this->assertNotNull($this->session_id, 'Session ID is set.');
  331. $this->assertNotIdentical($this->session_id, $session_id, 'Session ID has changed.');
  332. $this->drupalGet('<front>');
  333. $this->assertText('My account', 'User is logged in.');
  334. // Check that cart is now empty.
  335. $this->drupalGet('cart');
  336. $this->assertText('There are no products in your shopping cart.');
  337. }
  338. /**
  339. * Tests checkout complete functioning.
  340. */
  341. public function testCheckoutComplete() {
  342. // Payment notification is received first.
  343. $order_data = array('primary_email' => 'simpletest@ubercart.org');
  344. $order = $this->createOrder($order_data);
  345. uc_payment_enter($order->order_id, 'SimpleTest', $order->order_total);
  346. $output = uc_cart_complete_sale($order);
  347. // Check that a new account was created.
  348. $this->assertTrue(strpos($output['#message'], 'new account has been created') !== FALSE, 'Checkout message mentions new account.');
  349. // 2 e-mails: new account, customer invoice.
  350. $mails = $this->drupalGetMails();
  351. $this->assertEqual(count($mails), 2, '2 e-mails were sent.');
  352. variable_del('drupal_test_email_collector');
  353. $password = $mails[0]['params']['account']->password;
  354. $this->assertTrue(!empty($password), 'New password is not empty.');
  355. // In D7, new account emails do not contain the password.
  356. //$this->assertTrue(strpos($mails[0]['body'], $password) !== FALSE, 'Mail body contains password.');
  357. // Different user, sees the checkout page first.
  358. $order_data = array('primary_email' => 'simpletest2@ubercart.org');
  359. $order = $this->createOrder($order_data);
  360. $output = uc_cart_complete_sale($order, TRUE);
  361. uc_payment_enter($order->order_id, 'SimpleTest', $order->order_total);
  362. // 2 e-mails: new account, customer invoice.
  363. $mails = $this->drupalGetMails();
  364. $this->assertEqual(count($mails), 2, '2 e-mails were sent.');
  365. variable_del('drupal_test_email_collector');
  366. $password = $mails[0]['params']['account']->password;
  367. $this->assertTrue(!empty($password), 'New password is not empty.');
  368. // In D7, new account emails do not contain the password.
  369. //$this->assertTrue(strpos($mails[0]['body'], $password) !== FALSE, 'Mail body contains password.');
  370. // Same user, new order.
  371. $order = $this->createOrder($order_data);
  372. $output = uc_cart_complete_sale($order, TRUE);
  373. uc_payment_enter($order->order_id, 'SimpleTest', $order->order_total);
  374. // Check that no new account was created.
  375. $this->assertTrue(strpos($output['#message'], 'order has been attached to the account') !== FALSE, 'Checkout message mentions existing account.');
  376. // 1 e-mail: customer invoice.
  377. $mails = $this->drupalGetMails();
  378. $this->assertEqual(count($mails), 1, '1 e-mail was sent.');
  379. variable_del('drupal_test_email_collector');
  380. }
  381. public function testCheckoutRoleAssignment() {
  382. // Add role assignment to the test product.
  383. $rid = $this->drupalCreateRole(array('access content'));
  384. $this->drupalLogin($this->adminUser);
  385. $this->drupalPost('node/' . $this->product->nid . '/edit/features', array('feature' => 'role'), t('Add'));
  386. $this->drupalPost(NULL, array('uc_roles_role' => $rid), t('Save feature'));
  387. // Process an anonymous, shippable order.
  388. $item = clone $this->product;
  389. $item->qty = 1;
  390. $item->price = $item->sell_price;
  391. $item->data = array('shippable' => TRUE);
  392. $order = $this->createOrder(array(
  393. 'products' => array($item),
  394. ));
  395. uc_payment_enter($order->order_id, 'SimpleTest', $order->order_total);
  396. // Find the order uid.
  397. $uid = db_query("SELECT uid FROM {uc_orders} ORDER BY order_id DESC")->fetchField();
  398. $account = user_load($uid);
  399. $this->assertTrue(isset($account->roles[$rid]), 'New user was granted role.');
  400. $order = uc_order_load($order->order_id);
  401. $this->assertEqual($order->order_status, 'payment_received', 'Shippable order was set to payment received.');
  402. // 3 e-mails: new account, customer invoice, role assignment.
  403. $mails = $this->drupalGetMails();
  404. $this->assertEqual(count($mails), 3, '3 e-mails were sent.');
  405. variable_del('drupal_test_email_collector');
  406. // Test again with an existing email address and a non-shippable order.
  407. $item->data = array('shippable' => FALSE);
  408. $order = $this->createOrder(array(
  409. 'primary_email' => $this->customer->mail,
  410. 'products' => array($item),
  411. ));
  412. uc_payment_enter($order->order_id, 'SimpleTest', $order->order_total);
  413. $account = user_load($this->customer->uid);
  414. $this->assertTrue(isset($account->roles[$rid]), 'Existing user was granted role.');
  415. $order = uc_order_load($order->order_id);
  416. $this->assertEqual($order->order_status, 'completed', 'Non-shippable order was set to completed.');
  417. // 2 e-mails: customer invoice, role assignment.
  418. $mails = $this->drupalGetMails();
  419. $this->assertEqual(count($mails), 2, '2 e-mails were sent.');
  420. variable_del('drupal_test_email_collector');
  421. }
  422. /**
  423. * Tests that cart orders are marked abandoned after a timeout.
  424. */
  425. public function testCartOrderTimeout() {
  426. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  427. $this->drupalPost('cart', array(), 'Checkout');
  428. $this->assertText(
  429. t('Enter your billing address and information here.'),
  430. t('Viewed cart page: Billing pane has been displayed.')
  431. );
  432. // Build the panes.
  433. $zone_id = db_query_range('SELECT zone_id FROM {uc_zones} WHERE zone_country_id = :country ORDER BY rand()', 0, 1, array('country' => variable_get('uc_store_country', 840)))->fetchField();
  434. $oldname = $this->randomName(10);
  435. $edit = array(
  436. 'panes[delivery][delivery_first_name]' => $oldname,
  437. 'panes[delivery][delivery_last_name]' => $this->randomName(10),
  438. 'panes[delivery][delivery_street1]' => $this->randomName(10),
  439. 'panes[delivery][delivery_city]' => $this->randomName(10),
  440. 'panes[delivery][delivery_zone]' => $zone_id,
  441. 'panes[delivery][delivery_postal_code]' => mt_rand(10000, 99999),
  442. 'panes[billing][billing_first_name]' => $this->randomName(10),
  443. 'panes[billing][billing_last_name]' => $this->randomName(10),
  444. 'panes[billing][billing_street1]' => $this->randomName(10),
  445. 'panes[billing][billing_city]' => $this->randomName(10),
  446. 'panes[billing][billing_zone]' => $zone_id,
  447. 'panes[billing][billing_postal_code]' => mt_rand(10000, 99999),
  448. );
  449. // If the email address has not been set, and the user has not logged in,
  450. // add a primary email address.
  451. if (!isset($edit['panes[customer][primary_email]']) && !$this->loggedInUser) {
  452. $edit['panes[customer][primary_email]'] = $this->randomName(8) . '@example.com';
  453. }
  454. // Submit the checkout page.
  455. $this->drupalPost('cart/checkout', $edit, t('Review order'));
  456. $order_id = db_query("SELECT order_id FROM {uc_orders} WHERE delivery_first_name = :name", array(':name' => $oldname))->fetchField();
  457. if ($order_id) {
  458. // Go to a different page, then back to order to make sure
  459. // order_id is the same.
  460. $this->drupalGet('<front>');
  461. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  462. $this->drupalPost('cart', array(), 'Checkout');
  463. $this->assertRaw($oldname, 'Customer name was unchanged.');
  464. $this->drupalPost('cart/checkout', $edit, t('Review order'));
  465. $new_order_id = db_query("SELECT order_id FROM {uc_orders} WHERE delivery_first_name = :name", array(':name' => $edit['panes[delivery][delivery_first_name]']))->fetchField();
  466. $this->assertEqual($order_id, $new_order_id, 'Original order_id was reused.');
  467. // Jump 10 minutes into the future.
  468. db_update('uc_orders')
  469. ->fields(array(
  470. 'modified' => time() - UC_CART_ORDER_TIMEOUT - 1,
  471. ))
  472. ->condition('order_id', $order_id)
  473. ->execute();
  474. $old_order = uc_order_load($order_id);
  475. // Go to a different page, then back to order to verify that we are
  476. // using a new order.
  477. $this->drupalGet('<front>');
  478. $this->drupalPost('cart', array(), 'Checkout');
  479. $this->assertNoRaw($oldname, 'Customer name was cleared after timeout.');
  480. $newname = $this->randomName(10);
  481. $edit['panes[delivery][delivery_first_name]'] = $newname;
  482. $this->drupalPost('cart/checkout', $edit, t('Review order'));
  483. $new_order_id = db_query("SELECT order_id FROM {uc_orders} WHERE delivery_first_name = :name", array(':name' => $newname))->fetchField();
  484. $this->assertNotEqual($order_id, $new_order_id, 'New order was created after timeout.');
  485. // Verify that the status of old order is abandoned.
  486. $old_order = uc_order_load($order_id, TRUE);
  487. $this->assertEqual($old_order->order_status, 'abandoned', 'Original order was marked abandoned.');
  488. }
  489. else {
  490. $this->fail('No order was created.');
  491. }
  492. }
  493. /**
  494. * Tests functioning of customer information pane on checkout page.
  495. */
  496. public function testCustomerInformationCheckoutPane() {
  497. // Log in as a customer and add an item to the cart.
  498. $this->drupalLogin($this->customer);
  499. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
  500. $this->drupalPost('cart', array(), 'Checkout');
  501. // Test the customer information pane.
  502. $mail = $this->customer->mail;
  503. $this->assertText('Customer information');
  504. $this->assertText('Order information will be sent to your account e-mail listed below.');
  505. $this->assertText('E-mail address: ' . $mail);
  506. // Use the 'edit' link to change the email address on the account.
  507. $new_mail = $this->randomName() . '@example.com';
  508. $this->clickLink('edit');
  509. $data = array(
  510. 'current_pass' => $this->customer->pass_raw,
  511. 'mail' => $new_mail,
  512. );
  513. $this->drupalPost(NULL, $data, 'Save');
  514. // Test the updated email address.
  515. $this->assertText('Order information will be sent to your account e-mail listed below.');
  516. $this->assertNoText('E-mail address: ' . $mail);
  517. $this->assertText('E-mail address: ' . $new_mail);
  518. }
  519. }
  520. /**
  521. * Tests the cart settings page.
  522. */
  523. class UbercartCartSettingsTestCase extends UbercartTestHelper {
  524. public static function getInfo() {
  525. return array(
  526. 'name' => 'Cart settings',
  527. 'description' => 'Tests the cart settings page.',
  528. 'group' => 'Ubercart',
  529. );
  530. }
  531. /**
  532. * Tests add-to-cart redirection.
  533. */
  534. public function testAddToCartRedirect() {
  535. $this->drupalLogin($this->adminUser);
  536. $this->drupalGet('admin/store/settings/cart');
  537. $this->assertField(
  538. 'uc_add_item_redirect',
  539. t('Add to cart redirect field exists')
  540. );
  541. $redirect = $this->randomName(8);
  542. $this->drupalPost(
  543. 'admin/store/settings/cart',
  544. array('uc_add_item_redirect' => $redirect),
  545. t('Save configuration')
  546. );
  547. $this->drupalPost(
  548. 'node/' . $this->product->nid,
  549. array(),
  550. t('Add to cart')
  551. );
  552. $url_pass = ($this->getUrl() == url($redirect, array('absolute' => TRUE)));
  553. $this->assertTrue(
  554. $url_pass,
  555. t('Add to cart redirect takes user to the correct URL.')
  556. );
  557. $this->drupalPost(
  558. 'admin/store/settings/cart',
  559. array('uc_add_item_redirect' => '<none>'),
  560. t('Save configuration')
  561. );
  562. $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'), array('query' => array('test' => 'querystring')));
  563. $url = url('node/' . $this->product->nid, array('absolute' => TRUE, 'query' => array('test' => 'querystring')));
  564. $this->assertTrue($this->getUrl() == $url, 'Add to cart no-redirect works with a query string.');
  565. }
  566. /**
  567. * Tests minimum subtotal for checkout.
  568. */
  569. public function testMinimumSubtotal() {
  570. $this->drupalLogin($this->adminUser);
  571. $this->drupalGet('admin/store/settings/cart');
  572. $this->assertField(
  573. 'uc_minimum_subtotal',
  574. t('Minimum order subtotal field exists')
  575. );
  576. $minimum_subtotal = mt_rand(2, 9999);
  577. $this->drupalPost(
  578. NULL,
  579. array('uc_minimum_subtotal' => $minimum_subtotal),
  580. t('Save configuration')
  581. );
  582. // Create two products, one below the minimum price and one above.
  583. $product_below_limit = $this->createProduct(array('sell_price' => $minimum_subtotal - 1));
  584. $product_above_limit = $this->createProduct(array('sell_price' => $minimum_subtotal + 1));
  585. $this->drupalLogout();
  586. // Checks if the lower priced product triggers the minimum price logic.
  587. $this->drupalPost(
  588. 'node/' . $product_below_limit->nid,
  589. array(),
  590. t('Add to cart')
  591. );
  592. $this->drupalPost('cart',
  593. array(),
  594. t('Checkout')
  595. );
  596. $this->assertRaw(
  597. 'The minimum order subtotal for checkout is',
  598. t('Prevented checkout below the minimum order total.')
  599. );
  600. // Add another product to the cart, and verify that we land on
  601. // the checkout page.
  602. $this->drupalPost(
  603. 'node/' . $product_above_limit->nid,
  604. array(),
  605. t('Add to cart')
  606. );
  607. $this->drupalPost(
  608. 'cart',
  609. array(),
  610. t('Checkout')
  611. );
  612. $this->assertText('Enter your billing address and information here.');
  613. }
  614. public function testEmptyCart() {
  615. // Test that the feature is not enabled by default.
  616. $this->drupalPost('node/' . $this->product->nid, array(), 'Add to cart');
  617. $this->assertNoRaw('Empty cart');
  618. // Test the admin settings itself.
  619. $this->drupalLogin($this->adminUser);
  620. $this->drupalGet('admin/store/settings/cart');
  621. $this->assertField('uc_cart_empty_button', 'Empty cart button checkbox found.');
  622. $this->drupalPost(NULL, array('uc_cart_empty_button' => TRUE), 'Save configuration');
  623. // Test the feature itself.
  624. $this->drupalGet('cart');
  625. $this->drupalPost(NULL, array(), 'Empty cart');
  626. $this->assertText('Are you sure you want to empty your shopping cart? ');
  627. $this->drupalPost(NULL, array(), 'Confirm');
  628. $this->assertText('There are no products in your shopping cart.');
  629. }
  630. /**
  631. * Tests that continue shopping link returns customer to the correct place.
  632. */
  633. public function testContinueShopping() {
  634. // Continue shopping link should take you back to the product page.
  635. $this->drupalPost(
  636. 'node/' . $this->product->nid,
  637. array(),
  638. t('Add to cart')
  639. );
  640. $this->assertLink(
  641. t('Continue shopping'),
  642. 0,
  643. t('Continue shopping link appears on the page.')
  644. );
  645. $links = $this->xpath('//a[@href="' . url('node/' . $this->product->nid, array('absolute' => FALSE)) . '"]');
  646. $this->assertTrue(
  647. isset($links[0]),
  648. t('Continue shopping link returns to the product page.')
  649. );
  650. $this->drupalLogin($this->adminUser);
  651. $this->drupalGet('admin/store/settings/cart');
  652. $this->assertField(
  653. 'uc_continue_shopping_type',
  654. t('Continue shopping element display field exists')
  655. );
  656. $this->assertField(
  657. 'uc_continue_shopping_url',
  658. t('Default continue shopping link URL field exists')
  659. );
  660. // Test continue shopping button that sends users to a fixed URL.
  661. $settings = array(
  662. 'uc_continue_shopping_type' => 'button',
  663. 'uc_continue_shopping_use_last_url' => FALSE,
  664. 'uc_continue_shopping_url' => $this->randomName(8),
  665. );
  666. $this->drupalPost(
  667. NULL,
  668. $settings,
  669. t('Save configuration')
  670. );
  671. $this->drupalPost(
  672. 'cart',
  673. array(),
  674. t('Continue shopping')
  675. );
  676. $url_pass = ($this->getUrl() == url($settings['uc_continue_shopping_url'],
  677. array('absolute' => TRUE)));
  678. $this->assertTrue(
  679. $url_pass,
  680. t('Continue shopping button takes the user to the correct URL.')
  681. );
  682. }
  683. /**
  684. * Tests the shopping cart page breadcrumb.
  685. */
  686. public function testCartBreadcrumb() {
  687. $this->drupalLogin($this->adminUser);
  688. $this->drupalGet('admin/store/settings/cart');
  689. $this->assertField(
  690. 'uc_cart_breadcrumb_text',
  691. t('Custom cart breadcrumb text field exists')
  692. );
  693. $this->assertField(
  694. 'uc_cart_breadcrumb_url',
  695. t('Custom cart breadcrumb URL')
  696. );
  697. $settings = array(
  698. 'uc_cart_breadcrumb_text' => $this->randomName(8),
  699. 'uc_cart_breadcrumb_url' => $this->randomName(7),
  700. );
  701. $this->drupalPost(
  702. NULL,
  703. $settings,
  704. t('Save configuration')
  705. );
  706. $this->drupalPost(
  707. 'node/' . $this->product->nid,
  708. array(),
  709. t('Add to cart')
  710. );
  711. $this->assertLink(
  712. $settings['uc_cart_breadcrumb_text'],
  713. 0,
  714. t('The breadcrumb link text is set correctly.')
  715. );
  716. $links = $this->xpath('//a[@href="' . url($settings['uc_cart_breadcrumb_url']) . '"]');
  717. $this->assertTrue(
  718. isset($links[0]),
  719. t('The breadcrumb link is set correctly.')
  720. );
  721. }
  722. }
  723. /**
  724. * Tests the checkout settings page.
  725. */
  726. class UbercartCheckoutSettingsTestCase extends UbercartTestHelper {
  727. public static function getInfo() {
  728. return array(
  729. 'name' => 'Checkout settings',
  730. 'description' => 'Tests the checkout settings page.',
  731. 'group' => 'Ubercart',
  732. );
  733. }
  734. /**
  735. * Tests enabling checkout functionality.
  736. */
  737. public function testEnableCheckout() {
  738. $this->drupalLogin($this->adminUser);
  739. $this->drupalGet('admin/store/settings/checkout');
  740. $this->assertField(
  741. 'uc_checkout_enabled',
  742. t('Enable checkout field exists')
  743. );
  744. $this->drupalPost(
  745. 'admin/store/settings/checkout',
  746. array('uc_checkout_enabled' => FALSE),
  747. t('Save configuration')
  748. );
  749. $this->drupalPost(
  750. 'node/' . $this->product->nid,
  751. array(),
  752. t('Add to cart')
  753. );
  754. $this->assertNoRaw(t('Checkout'));
  755. $buttons = $this->xpath('//input[@value="' . t('Checkout') . '"]');
  756. $this->assertFalse(
  757. isset($buttons[0]),
  758. t('The checkout button is not shown.')
  759. );
  760. }
  761. /**
  762. * Tests anonymous checkout functionality.
  763. */
  764. public function testAnonymousCheckout() {
  765. $this->drupalLogin($this->adminUser);
  766. $this->drupalGet('admin/store/settings/checkout');
  767. $this->assertField(
  768. 'uc_checkout_anonymous',
  769. t('Anonymous checkout field exists')
  770. );
  771. $this->drupalPost(
  772. 'admin/store/settings/checkout',
  773. array('uc_checkout_anonymous' => FALSE),
  774. t('Save configuration')
  775. );
  776. $this->drupalLogout();
  777. $this->drupalPost(
  778. 'node/' . $this->product->nid,
  779. array(),
  780. t('Add to cart')
  781. );
  782. $this->drupalPost(
  783. 'cart',
  784. array(), 'Checkout');
  785. $this->assertNoText(
  786. 'Enter your billing address and information here.',
  787. t('The checkout page is not displayed.')
  788. );
  789. }
  790. }