diff --git a/src/Tests/AuctionWinTest.php b/src/Tests/AuctionWinTest.php new file mode 100644 index 0000000..d59acda --- /dev/null +++ b/src/Tests/AuctionWinTest.php @@ -0,0 +1,111 @@ + 'Auction Win Test', + 'description' => 'Tests cases for when an user wins an auction.', + 'group' => 'Commerce Auction', + ); + } + + /** + * {@inheritdoc} + */ + public function setUp(array $modules = array(), array $permissions = array()) { + parent::setUp($modules, $permissions); + + $this->product = $this->createAuctionProduct(); + $this->display = $this->createAuctionProductDisplay($this->product->product_id); + $this->customer = $this->createUserWithPermissionHelper(array('store customer', 'auction customer')); + } + + /** + * Tests if a product won with an auction can be ordered. + */ + public function testAuctionWinning() { + // Login as customer and place a bid. + $this->drupalLogin($this->customer); + $this->placeBid($this->display->nid, 60); + + // Let the auction end. + $this->endAuction($this->display); + + // Go to auction node to place the auction product in the cart. + $this->drupalGet('node/' . $this->display->nid); + + // Assert that the product is actually in the cart. + $order = $this->loadCommerceCartOrder($this->customer->uid); + $this->assertAuctionProductAddedToCart($order, $this->product, $this->customer); + + // And checkout. + $this->checkout(); + + // @todo Ensure that the product isn't added to the cart again. +// $this->drupalGet('node/' . $this->display->nid); +// $this->assertFalse($this->loadCommerceCartOrder($this->customer->uid)); +// $this->drupalGet('cart'); +// $this->assertText('Your shopping cart is empty.'); + } + + /** + * Tests that only the highest bidder wins the auction. + */ + public function testHighestBidWinsAuction() { + // Login as customer and place a bid. + $this->drupalLogin($this->customer); + $this->placeBid($this->display->nid, 60); + + // Let an other customer place a higher bid. + $customer2 = $this->createUserWithPermissionHelper(array('store customer', 'auction customer')); + $this->drupalLogin($customer2); + $this->placeBid($this->display->nid, 70); + + // Let the auction end. + $this->endAuction($this->display); + + // Assert that customer 1 did not won the auction. + $this->drupalLogin($this->customer); + $this->drupalGet('node/' . $this->display->nid); + $this->assertFalse($this->loadCommerceCartOrder($this->customer->uid)); + $this->drupalGet('cart'); + $this->assertText('Your shopping cart is empty.'); + + // Assert that customer 2 won the auction. + $this->drupalLogin($customer2); + $order = $this->loadCommerceCartOrder($customer2); + $this->assertAuctionProductAddedToCart($order, $this->product, $customer2); + } + +} diff --git a/src/Tests/TestBase.php b/src/Tests/TestBase.php index 8c2b548..51d3dc5 100644 --- a/src/Tests/TestBase.php +++ b/src/Tests/TestBase.php @@ -167,6 +167,51 @@ abstract class TestBase extends CommerceBaseTestCase { } /** + * Removes lock from commerce order entities. + */ + protected function releaseCommerceOrderLock() { + entity_get_controller('commerce_order')->resetCache(); + } + + /** + * Loads a single commerce order for the given user without lock. + * + * @param int $uid + * The user to load a cart order for. + * + * @return object + * A commerce order, if found. + * False otherwise. + */ + protected function loadCommerceCartOrder($uid) { + drupal_static_reset('commerce_cart_order_id'); + $order = commerce_cart_order_load($uid); + // Reset the cache as we don't want to keep the lock. + $this->releaseCommerceOrderLock(); + + return $order; + } + + /** + * Loads a single commerce order without lock. + * + * @param int $order_id + * ID of the order to load. + * + * @return object + * A commerce order, if found. + * False otherwise. + */ + protected function loadCommerceOrder($order_id, $reset = FALSE) { + $orders = commerce_order_load_multiple(array($order_id), array(), $reset); + $order = reset($orders); + // Reset the cache as we don't want to keep the lock. + $this->releaseCommerceOrderLock(); + + return $order; + } + + /** * Places a bid. * * @param int $nid @@ -190,6 +235,93 @@ abstract class TestBase extends CommerceBaseTestCase { } /** + * Ends an auction by changing the auction timeout to one second in the past. + * + * @param object $product_node + * The product node to end an auction for. + */ + protected function endAuction($product_node) { + $product_node->auction_timeout[LANGUAGE_NONE][0]['value'] = REQUEST_TIME -1; + node_save($product_node); + } + + /** + * Perform a checkout. + * + * Taken from CommerceCheckoutTestProcess::testCommerceCheckoutProcessAuthenticatedUser(). + * + * @see CommerceCheckoutTestProcess::testCommerceCheckoutProcessAuthenticatedUser() + */ + protected function checkout() { + // Load existing cart order. + $order = $this->loadCommerceCartOrder($this->loggedInUser->uid); + if (!$order) { + $this->fail('Failed to checkout. No cart order exists.'); + return; + } + + $this->drupalGet($this->getCommerceUrl('checkout')); + + // Generate random information, as city, postal code, etc. + $address_info = $this->generateAddressInformation(); + + // Check if the page resolves and if the default panes are present. + $this->assertResponse(200, t('The owner of the order can access to the checkout page')); + $this->assertTitle(t('Checkout') . ' | Drupal', t('Title of the checkout phase is correct')); + $this->assertText(t('Shopping cart contents'), t('Shopping cart contents pane is present')); + $this->assertText(t('Billing information'), t('Billing information pane is present')); + + // We are testing with authenticated user, so no account information + // should appear. + $this->assertNoText(t('Account information'), t('Account information pane is not present')); + + // Fill in the billing address information. + $billing_pane = $this->xpath("//select[starts-with(@name, 'customer_profile_billing[commerce_customer_address]')]"); + $this->drupalPostAJAX(NULL, array((string) $billing_pane[0]['name'] => 'US'), (string) $billing_pane[0]['name']); + + // Check if the country has been selected correctly, this uses XPath as the + // ajax call replaces the element and the id may change. + $this->assertFieldByXPath("//select[starts-with(@id, 'edit-customer-profile-billing-commerce-customer-address')]//option[@selected='selected']", 'US', t('Country selected')); + + // Fill in the required information for billing pane, with a random State. + $info = array( + 'customer_profile_billing[commerce_customer_address][und][0][name_line]' => $address_info['name_line'], + 'customer_profile_billing[commerce_customer_address][und][0][thoroughfare]' => $address_info['thoroughfare'], + 'customer_profile_billing[commerce_customer_address][und][0][locality]' => $address_info['locality'], + 'customer_profile_billing[commerce_customer_address][und][0][administrative_area]' => 'KY', + 'customer_profile_billing[commerce_customer_address][und][0][postal_code]' => $address_info['postal_code'], + ); + $this->drupalPost(NULL, $info, t('Continue to next step')); + + // Check for default panes and information in this checkout phase. + $this->pass(t('Checking the default panes and the page information:')); + $this->assertTitle(t('Review order') . ' | Drupal', t('Title of the checkout phase \'Review order\' is correct')); + $this->assertText($address_info['name_line'], t('Billing information for \'name_line\' is correct')); + $this->assertText($address_info['thoroughfare'], t('Billing information for \'thoroughfare\' is correct')); + $this->assertText($address_info['locality'], t('Billing information for \'locality\' is correct')); + $this->assertText(trim($address_info['postal_code']), t('Billing information for \'postal_code\' is correct')); + $this->assertText('United States', t('Billing information country is correct')); + + // Reload the order to check the status. + $order = $this->loadCommerceOrder($order->order_id, TRUE); + + // At this point we should be in Checkout Review. + $this->assertEqual($order->status, 'checkout_review', t('Order status is \'Checkout Review\' in the review phase.')); + + // Finish checkout process. + $this->drupalPost(NULL, array(), t('Continue to next step')); + + // Reload the order directly from db to update status. + $order = $this->loadCommerceOrder($order->order_id, TRUE); + + // Order status should be pending when completing checkout process. + $this->assertEqual($order->status, 'pending', t('Order status is \'Pending\' after completing checkout')); + // Check if the completion message has been displayed. + $this->assertTitle(t('Checkout complete') . ' | Drupal', t('Title of the page is \'Checkout complete\' when finishing the checkout process')); + $this->assertText(t('Your order number is @order-number.', array('@order-number' => $order->order_number)), t('Completion message for the checkout is correctly displayed')); + } + + /** * Asserts that a bid was saved. * * @param int $nid @@ -232,4 +364,35 @@ abstract class TestBase extends CommerceBaseTestCase { $this->assertText($amount_display); } + /** + * Asserts that a auction product has been added to the cart. + * + * @param object $order + * A full loaded commerce_order object. + * @param object $product + * A full loaded commerce_product object. + * + * @return TRUE if the product is in the cart, FALSE otherwise. + */ + public function assertAuctionProductAddedToCart($order, $product) { + // The order should be in cart status. + $this->assertTrue(commerce_cart_order_is_cart($order), t('The order checked is in cart status')); + + $product_is_in_cart = FALSE; + // Loop through the line items looking for products. + foreach (entity_metadata_wrapper('commerce_order', $order)->commerce_line_items as $delta => $line_item_wrapper) { + // If this line item matches the product checked... + if ($line_item_wrapper->getBundle() == 'commerce_auction_lineitem' && + $line_item_wrapper->commerce_product->product_id->value() == $product->product_id) { + $product_is_in_cart = TRUE; + } + } + + $this->assertTrue($product_is_in_cart, t('Product !product_title is present in the cart', array('!product_title' => $product->title))); + + // Access to the cart page to check if the product is there. + $this->drupalGet($this->getCommerceUrl('cart')); + $this->assertText($product->title, t('Product !product_title is present in the cart view', array('!product_title' => $product->title))); + } + }