+ Log out)', 'woocommerce' ), '' . esc_html( $current_user->display_name ) . '', esc_url( wc_logout_url() ) ); -?>
+ ?> + -+ recent orders, manage your shipping and billing addresses, and edit your password and account details.', 'woocommerce' ), esc_url( wc_get_endpoint_url( 'orders' ) ), esc_url( wc_get_endpoint_url( 'edit-address' ) ), esc_url( wc_get_endpoint_url( 'edit-account' ) ) ); -?>
+ ?> + $commenter['comment_author'], 'required' => $name_email_required, ), - 'email' => array( + 'email' => array( 'label' => __( 'Email', 'woocommerce' ), 'type' => 'email', 'value' => $commenter['comment_author_email'], diff --git a/templates/single-product.php b/templates/single-product.php index 045317a3a99..66598ae6a26 100644 --- a/templates/single-product.php +++ b/templates/single-product.php @@ -10,8 +10,8 @@ * happen. When this occurs the version of the template file will be bumped and * the readme will list any important changes. * - * @see https://docs.woocommerce.com/document/template-structure/ - * @package WooCommerce/Templates + * @see https://docs.woocommerce.com/document/template-structure/ + * @package WooCommerce/Templates * @version 1.6.4 */ @@ -31,7 +31,8 @@ get_header( 'shop' ); ?> do_action( 'woocommerce_before_main_content' ); ?> - + + @@ -55,6 +56,7 @@ get_header( 'shop' ); ?> do_action( 'woocommerce_sidebar' ); ?> -is_in_stock() ) : ?> apply_filters( 'woocommerce_quantity_input_min', $product->get_min_purchase_quantity(), $product ), - 'max_value' => apply_filters( 'woocommerce_quantity_input_max', $product->get_max_purchase_quantity(), $product ), - 'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( wp_unslash( $_POST['quantity'] ) ) : $product->get_min_purchase_quantity(), // WPCS: CSRF ok, input var ok. - ) ); + woocommerce_quantity_input( + array( + 'min_value' => apply_filters( 'woocommerce_quantity_input_min', $product->get_min_purchase_quantity(), $product ), + 'max_value' => apply_filters( 'woocommerce_quantity_input_max', $product->get_max_purchase_quantity(), $product ), + 'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( wp_unslash( $_POST['quantity'] ) ) : $product->get_min_purchase_quantity(), // WPCS: CSRF ok, input var ok. + ) + ); do_action( 'woocommerce_after_add_to_cart_quantity' ); ?> diff --git a/templates/single-product/add-to-cart/variable.php b/templates/single-product/add-to-cart/variable.php index b553af148f9..e11fd49c8e7 100644 --- a/templates/single-product/add-to-cart/variable.php +++ b/templates/single-product/add-to-cart/variable.php @@ -38,11 +38,13 @@ do_action( 'woocommerce_before_add_to_cart_form' ); ?>get_price_html(); ?>
+get_price_html(); ?>
diff --git a/templates/single-product/product-image.php b/templates/single-product/product-image.php index 63a4addd153..e6a028c5ce1 100644 --- a/templates/single-product/product-image.php +++ b/templates/single-product/product-image.php @@ -26,12 +26,15 @@ global $product; $columns = apply_filters( 'woocommerce_product_thumbnails_columns', 4 ); $post_thumbnail_id = $product->get_image_id(); -$wrapper_classes = apply_filters( 'woocommerce_single_product_image_gallery_classes', array( - 'woocommerce-product-gallery', - 'woocommerce-product-gallery--' . ( $product->get_image_id() ? 'with-images' : 'without-images' ), - 'woocommerce-product-gallery--columns-' . absint( $columns ), - 'images', -) ); +$wrapper_classes = apply_filters( + 'woocommerce_single_product_image_gallery_classes', + array( + 'woocommerce-product-gallery', + 'woocommerce-product-gallery--' . ( $product->get_image_id() ? 'with-images' : 'without-images' ), + 'woocommerce-product-gallery--columns-' . absint( $columns ), + 'images', + ) +); ?>Hi there! I\'m a bike messenger by day, aspiring actor by night, and this is my website. I live in Los Angeles, have a great dog named Jack, and I like piña coladas. (And gettin\' caught in the rain.)\n\n...or something like this:\n\n
The XYZ Doohickey Company was founded in 1971, and has been providing quality doohickeys to the public ever since. Located in Gotham City, XYZ employs over 2,000 people and does all kinds of awesome things for the Gotham community.\n\nAs a new WordPress user, you should go to your dashboard to delete this page and create new pages for your content. Have fun!','Sample Page','','publish','closed','open','','sample-page','','','2017-12-13 19:58:04','2017-12-13 19:58:04','',0,'http://local.wordpress.test/?page_id=2',0,'page','',0),(3,1,'2017-12-13 20:01:36','0000-00-00 00:00:00','','Auto Draft','','auto-draft','open','open','','','','','2017-12-13 20:01:36','0000-00-00 00:00:00','',0,'http://local.wordpress.test/?p=3',0,'post','',0),(4,1,'2017-12-13 20:02:04','2017-12-13 20:02:04','','Shop','','publish','closed','closed','','shop','','','2017-12-13 20:02:04','2017-12-13 20:02:04','',0,'http://local.wordpress.test/shop/',0,'page','',0),(5,1,'2017-12-13 20:02:04','2017-12-13 20:02:04','[woocommerce_cart]','Cart','','publish','closed','closed','','cart','','','2017-12-13 20:02:04','2017-12-13 20:02:04','',0,'http://local.wordpress.test/cart/',0,'page','',0),(6,1,'2017-12-13 20:02:04','2017-12-13 20:02:04','[woocommerce_checkout]','Checkout','','publish','closed','closed','','checkout','','','2017-12-13 20:02:04','2017-12-13 20:02:04','',0,'http://local.wordpress.test/checkout/',0,'page','',0),(7,1,'2017-12-13 20:02:04','2017-12-13 20:02:04','[woocommerce_my_account]','My account','','publish','closed','closed','','my-account','','','2017-12-13 20:02:04','2017-12-13 20:02:04','',0,'http://local.wordpress.test/my-account/',0,'page','',0),(9,1,'2017-12-13 20:02:45','2017-12-13 20:02:45','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','V-Neck T-Shirt','This is a variable product.','publish','open','closed','','v-neck-t-shirt','','','2017-12-13 20:02:47','2017-12-13 20:02:47','',0,'http://local.wordpress.test/product/import-placeholder-for-woo-vneck-tee/',0,'product','',0),(10,1,'2017-12-13 20:02:45','2017-12-13 20:02:45','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','Hoodie','This is a variable product.','publish','open','closed','','hoodie','','','2017-12-13 20:02:49','2017-12-13 20:02:49','',0,'http://local.wordpress.test/product/import-placeholder-for-woo-hoodie/',0,'product','',0),(11,1,'2017-12-13 20:02:45','2017-12-13 20:02:45','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','Hoodie with Logo','This is a simple product.','publish','open','closed','','hoodie-with-logo','','','2017-12-13 20:02:51','2017-12-13 20:02:51','',0,'http://local.wordpress.test/product/import-placeholder-for-woo-hoodie-with-logo/',0,'product','',0),(12,1,'2017-12-13 20:02:45','2017-12-13 20:02:45','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','T-Shirt','This is a simple product.','publish','open','closed','','t-shirt','','','2017-12-13 20:02:54','2017-12-13 20:02:54','',0,'http://local.wordpress.test/product/import-placeholder-for-woo-tshirt/',0,'product','',0),(13,1,'2017-12-13 20:02:45','2017-12-13 20:02:45','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','Beanie','This is a simple product.','publish','open','closed','','beanie','','','2017-12-13 20:02:49','2017-12-13 20:02:49','',0,'http://local.wordpress.test/product/import-placeholder-for-woo-beanie/',0,'product','',0),(14,1,'2017-12-13 20:02:45','2017-12-13 20:02:45','','vneck-tee-3.jpg','','inherit','open','closed','','vneck-tee-3-jpg','','','2017-12-13 20:02:45','2017-12-13 20:02:45','',9,'http://local.wordpress.test/wp-content/uploads/2017/12/vneck-tee-3.jpg',0,'attachment','image/jpeg',0),(15,1,'2017-12-13 20:02:46','2017-12-13 20:02:46','','vnech-tee-green-3.jpg','','inherit','open','closed','','vnech-tee-green-3-jpg','','','2017-12-13 20:02:46','2017-12-13 20:02:46','',9,'http://local.wordpress.test/wp-content/uploads/2017/12/vnech-tee-green-3.jpg',0,'attachment','image/jpeg',0),(16,1,'2017-12-13 20:02:46','2017-12-13 20:02:46','','vnech-tee-blue-3.jpg','','inherit','open','closed','','vnech-tee-blue-3-jpg','','','2017-12-13 20:02:46','2017-12-13 20:02:46','',9,'http://local.wordpress.test/wp-content/uploads/2017/12/vnech-tee-blue-3.jpg',0,'attachment','image/jpeg',0),(17,1,'2017-12-13 20:02:47','2017-12-13 20:02:47','','hoodie-3.jpg','','inherit','open','closed','','hoodie-3-jpg','','','2017-12-13 20:02:47','2017-12-13 20:02:47','',10,'http://local.wordpress.test/wp-content/uploads/2017/12/hoodie-3.jpg',0,'attachment','image/jpeg',0),(18,1,'2017-12-13 20:02:47','2017-12-13 20:02:47','','hoodie-blue-3.jpg','','inherit','open','closed','','hoodie-blue-3-jpg','','','2017-12-13 20:02:47','2017-12-13 20:02:47','',10,'http://local.wordpress.test/wp-content/uploads/2017/12/hoodie-blue-3.jpg',0,'attachment','image/jpeg',0),(19,1,'2017-12-13 20:02:48','2017-12-13 20:02:48','','hoodie-green-3.jpg','','inherit','open','closed','','hoodie-green-3-jpg','','','2017-12-13 20:02:48','2017-12-13 20:02:48','',10,'http://local.wordpress.test/wp-content/uploads/2017/12/hoodie-green-3.jpg',0,'attachment','image/jpeg',0),(20,1,'2017-12-13 20:02:49','2017-12-13 20:02:49','','hoodie-with-logo-3.jpg','','inherit','open','closed','','hoodie-with-logo-3-jpg','','','2017-12-13 20:02:49','2017-12-13 20:02:49','',10,'http://local.wordpress.test/wp-content/uploads/2017/12/hoodie-with-logo-3.jpg',0,'attachment','image/jpeg',0),(21,1,'2017-12-13 20:02:49','2017-12-13 20:02:49','','beanie-3.jpg','','inherit','open','closed','','beanie-3-jpg','','','2017-12-13 20:02:49','2017-12-13 20:02:49','',13,'http://local.wordpress.test/wp-content/uploads/2017/12/beanie-3.jpg',0,'attachment','image/jpeg',0),(22,1,'2017-12-13 20:02:50','2017-12-13 20:02:50','','belt-3.jpg','','inherit','open','closed','','belt-3-jpg','','','2017-12-13 20:02:50','2017-12-13 20:02:50','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/belt-3.jpg',0,'attachment','image/jpeg',0),(23,1,'2017-12-13 20:02:50','2017-12-13 20:02:50','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','Belt','This is a simple product.','publish','open','closed','','belt','','','2017-12-13 20:02:50','2017-12-13 20:02:50','',0,'http://local.wordpress.test/product/belt/',0,'product','',0),(24,1,'2017-12-13 20:02:50','2017-12-13 20:02:50','','cap-3.jpg','','inherit','open','closed','','cap-3-jpg','','','2017-12-13 20:02:50','2017-12-13 20:02:50','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/cap-3.jpg',0,'attachment','image/jpeg',0),(25,1,'2017-12-13 20:02:51','2017-12-13 20:02:51','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','Cap','This is a simple product.','publish','open','closed','','cap','','','2017-12-13 20:02:51','2017-12-13 20:02:51','',0,'http://local.wordpress.test/product/cap/',0,'product','',0),(26,1,'2017-12-13 20:02:51','2017-12-13 20:02:51','','sunglasses-3.jpg','','inherit','open','closed','','sunglasses-3-jpg','','','2017-12-13 20:02:51','2017-12-13 20:02:51','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/sunglasses-3.jpg',0,'attachment','image/jpeg',0),(27,1,'2017-12-13 20:02:51','2017-12-13 20:02:51','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','Sunglasses','This is a simple product.','publish','open','closed','','sunglasses','','','2017-12-13 20:02:51','2017-12-13 20:02:51','',0,'http://local.wordpress.test/product/sunglasses/',0,'product','',0),(28,1,'2017-12-13 20:02:51','2017-12-13 20:02:51','','hoodie-with-pocket-3.jpg','','inherit','open','closed','','hoodie-with-pocket-3-jpg','','','2017-12-13 20:02:51','2017-12-13 20:02:51','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/hoodie-with-pocket-3.jpg',0,'attachment','image/jpeg',0),(29,1,'2017-12-13 20:02:52','2017-12-13 20:02:52','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','Hoodie with Pocket','This is a simple product.','publish','open','closed','','hoodie-with-pocket','','','2017-12-13 20:02:52','2017-12-13 20:02:52','',0,'http://local.wordpress.test/product/hoodie-with-pocket/',0,'product','',0),(30,1,'2017-12-13 20:02:52','2017-12-13 20:02:52','','hoodie-with-zipper-3.jpg','','inherit','open','closed','','hoodie-with-zipper-3-jpg','','','2017-12-13 20:02:52','2017-12-13 20:02:52','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/hoodie-with-zipper-3.jpg',0,'attachment','image/jpeg',0),(31,1,'2017-12-13 20:02:52','2017-12-13 20:02:52','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','Hoodie with Zipper','This is a simple product.','publish','open','closed','','hoodie-with-zipper','','','2017-12-13 20:02:52','2017-12-13 20:02:52','',0,'http://local.wordpress.test/product/hoodie-with-zipper/',0,'product','',0),(32,1,'2017-12-13 20:02:53','2017-12-13 20:02:53','','long-sleeve-tee-3.jpg','','inherit','open','closed','','long-sleeve-tee-3-jpg','','','2017-12-13 20:02:53','2017-12-13 20:02:53','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/long-sleeve-tee-3.jpg',0,'attachment','image/jpeg',0),(33,1,'2017-12-13 20:02:53','2017-12-13 20:02:53','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','Long Sleeve Tee','This is a simple product.','publish','open','closed','','long-sleeve-tee','','','2017-12-13 20:02:53','2017-12-13 20:02:53','',0,'http://local.wordpress.test/product/long-sleeve-tee/',0,'product','',0),(34,1,'2017-12-13 20:02:53','2017-12-13 20:02:53','','polo-3.jpg','','inherit','open','closed','','polo-3-jpg','','','2017-12-13 20:02:53','2017-12-13 20:02:53','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/polo-3.jpg',0,'attachment','image/jpeg',0),(35,1,'2017-12-13 20:02:54','2017-12-13 20:02:54','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','Polo','This is a simple product.','publish','open','closed','','polo','','','2017-12-13 20:02:54','2017-12-13 20:02:54','',0,'http://local.wordpress.test/product/polo/',0,'product','',0),(36,1,'2017-12-13 20:02:54','2017-12-13 20:02:54','','tshirt-3.jpg','','inherit','open','closed','','tshirt-3-jpg','','','2017-12-13 20:02:54','2017-12-13 20:02:54','',12,'http://local.wordpress.test/wp-content/uploads/2017/12/tshirt-3.jpg',0,'attachment','image/jpeg',0),(37,1,'2017-12-13 20:02:54','2017-12-13 20:02:54','','album-3.jpg','','inherit','open','closed','','album-3-jpg','','','2017-12-13 20:02:54','2017-12-13 20:02:54','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/album-3.jpg',0,'attachment','image/jpeg',0),(38,1,'2017-12-13 20:02:55','2017-12-13 20:02:55','Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sagittis orci ac odio dictum tincidunt. Donec ut metus leo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed luctus, dui eu sagittis sodales, nulla nibh sagittis augue, vel porttitor diam enim non metus. Vestibulum aliquam augue neque. Phasellus tincidunt odio eget ullamcorper efficitur. Cras placerat ut turpis pellentesque vulputate. Nam sed consequat tortor. Curabitur finibus sapien dolor. Ut eleifend tellus nec erat pulvinar dignissim. Nam non arcu purus. Vivamus et massa massa.','Album','This is a simple, virtual product.','publish','open','closed','','album','','','2017-12-13 20:02:55','2017-12-13 20:02:55','',0,'http://local.wordpress.test/product/album/',0,'product','',0),(39,1,'2017-12-13 20:02:55','2017-12-13 20:02:55','','single-3.jpg','','inherit','open','closed','','single-3-jpg','','','2017-12-13 20:02:55','2017-12-13 20:02:55','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/single-3.jpg',0,'attachment','image/jpeg',0),(40,1,'2017-12-13 20:02:55','2017-12-13 20:02:55','Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sagittis orci ac odio dictum tincidunt. Donec ut metus leo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed luctus, dui eu sagittis sodales, nulla nibh sagittis augue, vel porttitor diam enim non metus. Vestibulum aliquam augue neque. Phasellus tincidunt odio eget ullamcorper efficitur. Cras placerat ut turpis pellentesque vulputate. Nam sed consequat tortor. Curabitur finibus sapien dolor. Ut eleifend tellus nec erat pulvinar dignissim. Nam non arcu purus. Vivamus et massa massa.','Single','This is a simple, virtual product.','publish','open','closed','','single','','','2017-12-13 20:02:55','2017-12-13 20:02:55','',0,'http://local.wordpress.test/product/single/',0,'product','',0),(41,1,'2017-12-13 20:02:55','2017-12-13 20:02:55','','V-Neck T-Shirt - Red','','publish','closed','closed','','v-neck-t-shirt-red','','','2017-12-13 20:02:55','2017-12-13 20:02:55','',9,'http://local.wordpress.test/product/v-neck-t-shirt/',0,'product_variation','',0),(42,1,'2017-12-13 20:02:55','2017-12-13 20:02:55','','V-Neck T-Shirt - Green','','publish','closed','closed','','v-neck-t-shirt-green','','','2017-12-13 20:02:55','2017-12-13 20:02:55','',9,'http://local.wordpress.test/product/v-neck-t-shirt/',0,'product_variation','',0),(43,1,'2017-12-13 20:02:55','2017-12-13 20:02:55','','V-Neck T-Shirt - Blue','','publish','closed','closed','','v-neck-t-shirt-blue','','','2017-12-13 20:02:55','2017-12-13 20:02:55','',9,'http://local.wordpress.test/product/v-neck-t-shirt/',0,'product_variation','',0),(44,1,'2017-12-13 20:02:56','2017-12-13 20:02:56','','Hoodie - Red, No','','publish','closed','closed','','hoodie-red-no','','','2017-12-13 20:02:56','2017-12-13 20:02:56','',10,'http://local.wordpress.test/product/hoodie/',1,'product_variation','',0),(45,1,'2017-12-13 20:02:56','2017-12-13 20:02:56','','Hoodie - Green, No','','publish','closed','closed','','hoodie-green-no','','','2017-12-13 20:02:56','2017-12-13 20:02:56','',10,'http://local.wordpress.test/product/hoodie/',2,'product_variation','',0),(46,1,'2017-12-13 20:02:56','2017-12-13 20:02:56','','Hoodie - Blue, No','','publish','closed','closed','','hoodie-blue-no','','','2017-12-13 20:02:56','2017-12-13 20:02:56','',10,'http://local.wordpress.test/product/hoodie/',3,'product_variation','',0),(47,1,'2017-12-13 20:02:56','2017-12-13 20:02:56','','t-shirt-with-logo-3.jpg','','inherit','open','closed','','t-shirt-with-logo-3-jpg','','','2017-12-13 20:02:56','2017-12-13 20:02:56','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/t-shirt-with-logo-3.jpg',0,'attachment','image/jpeg',0),(48,1,'2017-12-13 20:02:56','2017-12-13 20:02:56','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','T-Shirt with Logo','This is a simple product.','publish','open','closed','','t-shirt-with-logo','','','2017-12-13 20:02:56','2017-12-13 20:02:56','',0,'http://local.wordpress.test/product/t-shirt-with-logo/',0,'product','',0),(49,1,'2017-12-13 20:02:56','2017-12-13 20:02:56','','beanie-with-logo-3.jpg','','inherit','open','closed','','beanie-with-logo-3-jpg','','','2017-12-13 20:02:56','2017-12-13 20:02:56','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/beanie-with-logo-3.jpg',0,'attachment','image/jpeg',0),(50,1,'2017-12-13 20:02:57','2017-12-13 20:02:57','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','Beanie with Logo','This is a simple product.','publish','open','closed','','beanie-with-logo','','','2017-12-13 20:02:57','2017-12-13 20:02:57','',0,'http://local.wordpress.test/product/beanie-with-logo/',0,'product','',0),(51,1,'2017-12-13 20:02:57','2017-12-13 20:02:57','','logo-3.jpg','','inherit','open','closed','','logo-3-jpg','','','2017-12-13 20:02:57','2017-12-13 20:02:57','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/logo-3.jpg',0,'attachment','image/jpeg',0),(52,1,'2017-12-13 20:02:57','2017-12-13 20:02:57','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','Logo Collection','This is a grouped product.','publish','open','closed','','logo-collection','','','2017-12-13 20:02:57','2017-12-13 20:02:57','',0,'http://local.wordpress.test/product/logo-collection/',0,'product','',0),(53,1,'2017-12-13 20:02:58','2017-12-13 20:02:58','','pennant-3.jpg','','inherit','open','closed','','pennant-3-jpg','','','2017-12-13 20:02:58','2017-12-13 20:02:58','',0,'http://local.wordpress.test/wp-content/uploads/2017/12/pennant-3.jpg',0,'attachment','image/jpeg',0),(54,1,'2017-12-13 20:02:58','2017-12-13 20:02:58','Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.','WordPress Pennant','This is an external product.','publish','open','closed','','wordpress-pennant','','','2017-12-13 20:02:58','2017-12-13 20:02:58','',0,'http://local.wordpress.test/product/wordpress-pennant/',0,'product','',0),(55,1,'2017-12-13 20:02:58','2017-12-13 20:02:58','','Hoodie - Blue, Yes','','publish','closed','closed','','hoodie-blue-yes','','','2017-12-13 20:02:58','2017-12-13 20:02:58','',10,'http://local.wordpress.test/product/hoodie/',0,'product_variation','',0); -/*!40000 ALTER TABLE `wp_posts` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_term_relationships` --- - -DROP TABLE IF EXISTS `wp_term_relationships`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_term_relationships` ( - `object_id` bigint(20) unsigned NOT NULL DEFAULT 0, - `term_taxonomy_id` bigint(20) unsigned NOT NULL DEFAULT 0, - `term_order` int(11) NOT NULL DEFAULT 0, - PRIMARY KEY (`object_id`,`term_taxonomy_id`), - KEY `term_taxonomy_id` (`term_taxonomy_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_term_relationships` --- - -LOCK TABLES `wp_term_relationships` WRITE; -/*!40000 ALTER TABLE `wp_term_relationships` DISABLE KEYS */; -INSERT INTO `wp_term_relationships` VALUES (1,1,0),(9,4,0),(9,8,0),(9,16,0),(9,20,0),(9,21,0),(9,22,0),(9,23,0),(9,24,0),(9,25,0),(10,4,0),(10,17,0),(10,20,0),(10,21,0),(10,22,0),(11,2,0),(11,17,0),(11,20,0),(12,2,0),(12,16,0),(12,27,0),(13,2,0),(13,18,0),(13,22,0),(23,2,0),(23,18,0),(25,2,0),(25,8,0),(25,18,0),(25,26,0),(27,2,0),(27,8,0),(27,18,0),(29,2,0),(29,6,0),(29,7,0),(29,8,0),(29,17,0),(29,27,0),(31,2,0),(31,8,0),(31,17,0),(33,2,0),(33,16,0),(33,21,0),(35,2,0),(35,16,0),(35,20,0),(38,2,0),(38,19,0),(40,2,0),(40,19,0),(48,2,0),(48,16,0),(48,27,0),(50,2,0),(50,18,0),(50,22,0),(52,3,0),(52,15,0),(54,5,0),(54,18,0); -/*!40000 ALTER TABLE `wp_term_relationships` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_term_taxonomy` --- - -DROP TABLE IF EXISTS `wp_term_taxonomy`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_term_taxonomy` ( - `term_taxonomy_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `term_id` bigint(20) unsigned NOT NULL DEFAULT 0, - `taxonomy` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `description` longtext COLLATE utf8mb4_unicode_ci NOT NULL, - `parent` bigint(20) unsigned NOT NULL DEFAULT 0, - `count` bigint(20) NOT NULL DEFAULT 0, - PRIMARY KEY (`term_taxonomy_id`), - UNIQUE KEY `term_id_taxonomy` (`term_id`,`taxonomy`), - KEY `taxonomy` (`taxonomy`) -) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_term_taxonomy` --- - -LOCK TABLES `wp_term_taxonomy` WRITE; -/*!40000 ALTER TABLE `wp_term_taxonomy` DISABLE KEYS */; -INSERT INTO `wp_term_taxonomy` VALUES (1,1,'category','',0,1),(2,2,'product_type','',0,14),(3,3,'product_type','',0,1),(4,4,'product_type','',0,2),(5,5,'product_type','',0,1),(6,6,'product_visibility','',0,1),(7,7,'product_visibility','',0,1),(8,8,'product_visibility','',0,5),(9,9,'product_visibility','',0,0),(10,10,'product_visibility','',0,0),(11,11,'product_visibility','',0,0),(12,12,'product_visibility','',0,0),(13,13,'product_visibility','',0,0),(14,14,'product_visibility','',0,0),(15,15,'product_cat','',0,1),(16,16,'product_cat','',0,5),(17,17,'product_cat','',0,4),(18,18,'product_cat','',0,6),(19,19,'product_cat','',0,2),(20,20,'pa_color','',0,4),(21,21,'pa_color','',0,3),(22,22,'pa_color','',0,4),(23,23,'pa_size','',0,1),(24,24,'pa_size','',0,1),(25,25,'pa_size','',0,1),(26,26,'pa_color','',0,1),(27,27,'pa_color','',0,3); -/*!40000 ALTER TABLE `wp_term_taxonomy` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_termmeta` --- - -DROP TABLE IF EXISTS `wp_termmeta`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_termmeta` ( - `meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `term_id` bigint(20) unsigned NOT NULL DEFAULT 0, - `meta_key` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, - `meta_value` longtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, - PRIMARY KEY (`meta_id`), - KEY `term_id` (`term_id`), - KEY `meta_key` (`meta_key`(191)) -) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_termmeta` --- - -LOCK TABLES `wp_termmeta` WRITE; -/*!40000 ALTER TABLE `wp_termmeta` DISABLE KEYS */; -INSERT INTO `wp_termmeta` VALUES (1,16,'order','0'),(2,17,'order','0'),(3,18,'order','0'),(4,19,'order','0'),(5,15,'product_count_product_cat','1'),(6,16,'product_count_product_cat','5'),(7,20,'order_pa_color','0'),(8,21,'order_pa_color','0'),(9,22,'order_pa_color','0'),(10,23,'order_pa_size','0'),(11,24,'order_pa_size','0'),(12,25,'order_pa_size','0'),(13,17,'product_count_product_cat','3'),(14,18,'product_count_product_cat','6'),(15,26,'order_pa_color','0'),(16,27,'order_pa_color','0'),(17,19,'product_count_product_cat','2'); -/*!40000 ALTER TABLE `wp_termmeta` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_terms` --- - -DROP TABLE IF EXISTS `wp_terms`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_terms` ( - `term_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `slug` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `term_group` bigint(10) NOT NULL DEFAULT 0, - PRIMARY KEY (`term_id`), - KEY `slug` (`slug`(191)), - KEY `name` (`name`(191)) -) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_terms` --- - -LOCK TABLES `wp_terms` WRITE; -/*!40000 ALTER TABLE `wp_terms` DISABLE KEYS */; -INSERT INTO `wp_terms` VALUES (1,'Uncategorized','uncategorized',0),(2,'simple','simple',0),(3,'grouped','grouped',0),(4,'variable','variable',0),(5,'external','external',0),(6,'exclude-from-search','exclude-from-search',0),(7,'exclude-from-catalog','exclude-from-catalog',0),(8,'featured','featured',0),(9,'outofstock','outofstock',0),(10,'rated-1','rated-1',0),(11,'rated-2','rated-2',0),(12,'rated-3','rated-3',0),(13,'rated-4','rated-4',0),(14,'rated-5','rated-5',0),(15,'Uncategorized','uncategorized',0),(16,'T-Shirts','t-shirts',0),(17,'Hoodies','hoodies',0),(18,'Accessories','accessories',0),(19,'Music','music',0),(20,'Blue','blue',0),(21,'Green','green',0),(22,'Red','red',0),(23,'Large','large',0),(24,'Medium','medium',0),(25,'Small','small',0),(26,'Yellow','yellow',0),(27,'Gray','gray',0); -/*!40000 ALTER TABLE `wp_terms` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_usermeta` --- - -DROP TABLE IF EXISTS `wp_usermeta`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_usermeta` ( - `umeta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `user_id` bigint(20) unsigned NOT NULL DEFAULT 0, - `meta_key` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, - `meta_value` longtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, - PRIMARY KEY (`umeta_id`), - KEY `user_id` (`user_id`), - KEY `meta_key` (`meta_key`(191)) -) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_usermeta` --- - -LOCK TABLES `wp_usermeta` WRITE; -/*!40000 ALTER TABLE `wp_usermeta` DISABLE KEYS */; -INSERT INTO `wp_usermeta` VALUES (1,1,'nickname','admin'),(2,1,'first_name',''),(3,1,'last_name',''),(4,1,'description',''),(5,1,'rich_editing','true'),(6,1,'syntax_highlighting','true'),(7,1,'comment_shortcuts','false'),(8,1,'admin_color','fresh'),(9,1,'use_ssl','0'),(10,1,'show_admin_bar_front','true'),(11,1,'locale',''),(12,1,'wp_capabilities','a:1:{s:13:\"administrator\";b:1;}'),(13,1,'wp_user_level','10'),(14,1,'dismissed_wp_pointers',''),(15,1,'show_welcome_panel','1'),(16,1,'session_tokens','a:1:{s:64:\"ef2e26f650431f06bcbff0857384ff8d74b838ed8670559b5d4a328f376ef802\";a:4:{s:10:\"expiration\";i:1528977468;s:2:\"ip\";s:12:\"192.168.50.1\";s:2:\"ua\";s:76:\"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0\";s:5:\"login\";i:1528804668;}}'),(17,1,'wp_dashboard_quick_press_last_post_id','3'),(18,1,'community-events-location','a:1:{s:2:\"ip\";s:12:\"192.168.50.0\";}'),(19,1,'_woocommerce_persistent_cart_1','a:1:{s:4:\"cart\";a:1:{s:32:\"6512bd43d9caa6e02c990b0a82652dca\";a:10:{s:3:\"key\";s:32:\"6512bd43d9caa6e02c990b0a82652dca\";s:10:\"product_id\";i:11;s:12:\"variation_id\";i:0;s:9:\"variation\";a:0:{}s:8:\"quantity\";i:1;s:13:\"line_tax_data\";a:2:{s:8:\"subtotal\";a:0:{}s:5:\"total\";a:0:{}}s:13:\"line_subtotal\";d:45;s:17:\"line_subtotal_tax\";i:0;s:10:\"line_total\";d:45;s:8:\"line_tax\";i:0;}}}'),(20,1,'wp_product_import_error_log','a:0:{}'),(21,2,'nickname','Customer'),(22,2,'first_name',''),(23,2,'last_name',''),(24,2,'description',''),(25,2,'rich_editing','true'),(26,2,'syntax_highlighting','true'),(27,2,'comment_shortcuts','false'),(28,2,'admin_color','fresh'),(29,2,'use_ssl','0'),(30,2,'show_admin_bar_front','true'),(31,2,'locale',''),(32,2,'wp_capabilities','a:1:{s:11:\"contributor\";b:1;}'),(33,2,'wp_user_level','1'),(34,2,'dismissed_wp_pointers',''),(35,1,'wc_last_active','1528761600'),(36,1,'wp_user-settings','libraryContent=browse&editor=html'),(37,1,'wp_user-settings-time','1528804668'),(38,2,'wc_last_active','1528761600'),(39,1,'dismissed_store_notice_setting_moved_notice','1'); -/*!40000 ALTER TABLE `wp_usermeta` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_users` --- - -DROP TABLE IF EXISTS `wp_users`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_users` ( - `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `user_login` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `user_pass` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `user_nicename` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `user_email` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `user_url` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `user_registered` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', - `user_activation_key` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `user_status` int(11) NOT NULL DEFAULT 0, - `display_name` varchar(250) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - PRIMARY KEY (`ID`), - KEY `user_login_key` (`user_login`), - KEY `user_nicename` (`user_nicename`), - KEY `user_email` (`user_email`) -) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_users` --- - -LOCK TABLES `wp_users` WRITE; -/*!40000 ALTER TABLE `wp_users` DISABLE KEYS */; -INSERT INTO `wp_users` VALUES (1,'admin','$P$Bvfd2NT05h.eCnc/5lt6dyqIpsGHYj/','admin','test@example.com','','2017-12-13 19:58:04','',0,'admin'),(2,'Customer','$P$B4FEN56HyJmGL.Y4t3hj4d7UV4MKce1','customer','customer@example.com','','2017-12-13 20:04:17','',0,'Customer'); -/*!40000 ALTER TABLE `wp_users` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_wc_download_log` --- - -DROP TABLE IF EXISTS `wp_wc_download_log`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_wc_download_log` ( - `download_log_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `timestamp` datetime NOT NULL, - `permission_id` bigint(20) unsigned NOT NULL, - `user_id` bigint(20) unsigned DEFAULT NULL, - `user_ip_address` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT '', - PRIMARY KEY (`download_log_id`), - KEY `permission_id` (`permission_id`), - KEY `timestamp` (`timestamp`), - CONSTRAINT `fk_wp_wc_download_log_permission_id` FOREIGN KEY (`permission_id`) REFERENCES `wp_woocommerce_downloadable_product_permissions` (`permission_id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_wc_download_log` --- - -LOCK TABLES `wp_wc_download_log` WRITE; -/*!40000 ALTER TABLE `wp_wc_download_log` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_wc_download_log` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_wc_webhooks` --- - -DROP TABLE IF EXISTS `wp_wc_webhooks`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_wc_webhooks` ( - `webhook_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `status` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, - `name` text COLLATE utf8mb4_unicode_ci NOT NULL, - `user_id` bigint(20) unsigned NOT NULL, - `delivery_url` text COLLATE utf8mb4_unicode_ci NOT NULL, - `secret` text COLLATE utf8mb4_unicode_ci NOT NULL, - `topic` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, - `date_created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', - `date_created_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', - `date_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', - `date_modified_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', - `api_version` smallint(4) NOT NULL, - `failure_count` smallint(10) NOT NULL DEFAULT 0, - `pending_delivery` tinyint(1) NOT NULL DEFAULT 0, - PRIMARY KEY (`webhook_id`), - KEY `user_id` (`user_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_wc_webhooks` --- - -LOCK TABLES `wp_wc_webhooks` WRITE; -/*!40000 ALTER TABLE `wp_wc_webhooks` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_wc_webhooks` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_api_keys` --- - -DROP TABLE IF EXISTS `wp_woocommerce_api_keys`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_api_keys` ( - `key_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `user_id` bigint(20) unsigned NOT NULL, - `description` varchar(200) COLLATE utf8mb4_unicode_ci DEFAULT NULL, - `permissions` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL, - `consumer_key` char(64) COLLATE utf8mb4_unicode_ci NOT NULL, - `consumer_secret` char(43) COLLATE utf8mb4_unicode_ci NOT NULL, - `nonces` longtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, - `truncated_key` char(7) COLLATE utf8mb4_unicode_ci NOT NULL, - `last_access` datetime DEFAULT NULL, - PRIMARY KEY (`key_id`), - KEY `consumer_key` (`consumer_key`), - KEY `consumer_secret` (`consumer_secret`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_api_keys` --- - -LOCK TABLES `wp_woocommerce_api_keys` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_api_keys` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_woocommerce_api_keys` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_attribute_taxonomies` --- - -DROP TABLE IF EXISTS `wp_woocommerce_attribute_taxonomies`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_attribute_taxonomies` ( - `attribute_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `attribute_name` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, - `attribute_label` varchar(200) COLLATE utf8mb4_unicode_ci DEFAULT NULL, - `attribute_type` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, - `attribute_orderby` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, - `attribute_public` int(1) NOT NULL DEFAULT 1, - PRIMARY KEY (`attribute_id`), - KEY `attribute_name` (`attribute_name`(20)) -) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_attribute_taxonomies` --- - -LOCK TABLES `wp_woocommerce_attribute_taxonomies` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_attribute_taxonomies` DISABLE KEYS */; -INSERT INTO `wp_woocommerce_attribute_taxonomies` VALUES (1,'color','Color','select','menu_order',0),(2,'size','Size','select','menu_order',0); -/*!40000 ALTER TABLE `wp_woocommerce_attribute_taxonomies` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_downloadable_product_permissions` --- - -DROP TABLE IF EXISTS `wp_woocommerce_downloadable_product_permissions`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_downloadable_product_permissions` ( - `permission_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `download_id` varchar(36) COLLATE utf8mb4_unicode_ci NOT NULL, - `product_id` bigint(20) unsigned NOT NULL, - `order_id` bigint(20) unsigned NOT NULL DEFAULT 0, - `order_key` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, - `user_email` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, - `user_id` bigint(20) unsigned DEFAULT NULL, - `downloads_remaining` varchar(9) COLLATE utf8mb4_unicode_ci DEFAULT NULL, - `access_granted` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', - `access_expires` datetime DEFAULT NULL, - `download_count` bigint(20) unsigned NOT NULL DEFAULT 0, - PRIMARY KEY (`permission_id`), - KEY `download_order_key_product` (`product_id`,`order_id`,`order_key`(16),`download_id`), - KEY `download_order_product` (`download_id`,`order_id`,`product_id`), - KEY `order_id` (`order_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_downloadable_product_permissions` --- - -LOCK TABLES `wp_woocommerce_downloadable_product_permissions` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_downloadable_product_permissions` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_woocommerce_downloadable_product_permissions` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_log` --- - -DROP TABLE IF EXISTS `wp_woocommerce_log`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_log` ( - `log_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `timestamp` datetime NOT NULL, - `level` smallint(4) NOT NULL, - `source` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, - `message` longtext COLLATE utf8mb4_unicode_ci NOT NULL, - `context` longtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, - PRIMARY KEY (`log_id`), - KEY `level` (`level`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_log` --- - -LOCK TABLES `wp_woocommerce_log` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_log` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_woocommerce_log` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_order_itemmeta` --- - -DROP TABLE IF EXISTS `wp_woocommerce_order_itemmeta`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_order_itemmeta` ( - `meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `order_item_id` bigint(20) unsigned NOT NULL, - `meta_key` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, - `meta_value` longtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, - PRIMARY KEY (`meta_id`), - KEY `order_item_id` (`order_item_id`), - KEY `meta_key` (`meta_key`(32)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_order_itemmeta` --- - -LOCK TABLES `wp_woocommerce_order_itemmeta` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_order_itemmeta` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_woocommerce_order_itemmeta` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_order_items` --- - -DROP TABLE IF EXISTS `wp_woocommerce_order_items`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_order_items` ( - `order_item_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `order_item_name` text COLLATE utf8mb4_unicode_ci NOT NULL, - `order_item_type` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `order_id` bigint(20) unsigned NOT NULL, - PRIMARY KEY (`order_item_id`), - KEY `order_id` (`order_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_order_items` --- - -LOCK TABLES `wp_woocommerce_order_items` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_order_items` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_woocommerce_order_items` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_payment_tokenmeta` --- - -DROP TABLE IF EXISTS `wp_woocommerce_payment_tokenmeta`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_payment_tokenmeta` ( - `meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `payment_token_id` bigint(20) unsigned NOT NULL, - `meta_key` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, - `meta_value` longtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, - PRIMARY KEY (`meta_id`), - KEY `payment_token_id` (`payment_token_id`), - KEY `meta_key` (`meta_key`(32)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_payment_tokenmeta` --- - -LOCK TABLES `wp_woocommerce_payment_tokenmeta` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_payment_tokenmeta` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_woocommerce_payment_tokenmeta` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_payment_tokens` --- - -DROP TABLE IF EXISTS `wp_woocommerce_payment_tokens`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_payment_tokens` ( - `token_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `gateway_id` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, - `token` text COLLATE utf8mb4_unicode_ci NOT NULL, - `user_id` bigint(20) unsigned NOT NULL DEFAULT 0, - `type` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, - `is_default` tinyint(1) NOT NULL DEFAULT 0, - PRIMARY KEY (`token_id`), - KEY `user_id` (`user_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_payment_tokens` --- - -LOCK TABLES `wp_woocommerce_payment_tokens` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_payment_tokens` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_woocommerce_payment_tokens` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_sessions` --- - -DROP TABLE IF EXISTS `wp_woocommerce_sessions`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_sessions` ( - `session_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `session_key` char(32) COLLATE utf8mb4_unicode_ci NOT NULL, - `session_value` longtext COLLATE utf8mb4_unicode_ci NOT NULL, - `session_expiry` bigint(20) unsigned NOT NULL, - PRIMARY KEY (`session_id`), - UNIQUE KEY `session_key` (`session_key`) -) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_sessions` --- - -LOCK TABLES `wp_woocommerce_sessions` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_sessions` DISABLE KEYS */; -INSERT INTO `wp_woocommerce_sessions` VALUES (6,'1','a:12:{s:4:\"cart\";s:354:\"a:1:{s:32:\"6512bd43d9caa6e02c990b0a82652dca\";a:10:{s:3:\"key\";s:32:\"6512bd43d9caa6e02c990b0a82652dca\";s:10:\"product_id\";i:11;s:12:\"variation_id\";i:0;s:9:\"variation\";a:0:{}s:8:\"quantity\";i:1;s:13:\"line_tax_data\";a:2:{s:8:\"subtotal\";a:0:{}s:5:\"total\";a:0:{}}s:13:\"line_subtotal\";d:45;s:17:\"line_subtotal_tax\";i:0;s:10:\"line_total\";d:45;s:8:\"line_tax\";i:0;}}\";s:11:\"cart_totals\";s:405:\"a:15:{s:8:\"subtotal\";s:5:\"45.00\";s:12:\"subtotal_tax\";d:0;s:14:\"shipping_total\";s:4:\"0.00\";s:12:\"shipping_tax\";d:0;s:14:\"shipping_taxes\";a:0:{}s:14:\"discount_total\";d:0;s:12:\"discount_tax\";d:0;s:19:\"cart_contents_total\";s:5:\"45.00\";s:17:\"cart_contents_tax\";d:0;s:19:\"cart_contents_taxes\";a:0:{}s:9:\"fee_total\";s:4:\"0.00\";s:7:\"fee_tax\";d:0;s:9:\"fee_taxes\";a:0:{}s:5:\"total\";s:5:\"45.00\";s:9:\"total_tax\";d:0;}\";s:15:\"applied_coupons\";s:6:\"a:0:{}\";s:22:\"coupon_discount_totals\";s:6:\"a:0:{}\";s:26:\"coupon_discount_tax_totals\";s:6:\"a:0:{}\";s:21:\"removed_cart_contents\";s:6:\"a:0:{}\";s:8:\"customer\";s:704:\"a:26:{s:2:\"id\";s:1:\"1\";s:13:\"date_modified\";s:0:\"\";s:8:\"postcode\";s:0:\"\";s:4:\"city\";s:0:\"\";s:9:\"address_1\";s:0:\"\";s:7:\"address\";s:0:\"\";s:9:\"address_2\";s:0:\"\";s:5:\"state\";s:0:\"\";s:7:\"country\";s:2:\"BR\";s:17:\"shipping_postcode\";s:0:\"\";s:13:\"shipping_city\";s:0:\"\";s:18:\"shipping_address_1\";s:0:\"\";s:16:\"shipping_address\";s:0:\"\";s:18:\"shipping_address_2\";s:0:\"\";s:14:\"shipping_state\";s:0:\"\";s:16:\"shipping_country\";s:2:\"BR\";s:13:\"is_vat_exempt\";s:0:\"\";s:19:\"calculated_shipping\";s:0:\"\";s:10:\"first_name\";s:0:\"\";s:9:\"last_name\";s:0:\"\";s:7:\"company\";s:0:\"\";s:5:\"phone\";s:0:\"\";s:5:\"email\";s:16:\"test@example.com\";s:19:\"shipping_first_name\";s:0:\"\";s:18:\"shipping_last_name\";s:0:\"\";s:16:\"shipping_company\";s:0:\"\";}\";s:21:\"chosen_payment_method\";s:6:\"cheque\";s:22:\"shipping_for_package_0\";s:382:\"a:2:{s:12:\"package_hash\";s:40:\"wc_ship_bd52cdac5f5ccf2ce73c37da93809cd7\";s:5:\"rates\";a:1:{s:11:\"flat_rate:1\";O:16:\"WC_Shipping_Rate\":2:{s:7:\"\0*\0data\";a:6:{s:2:\"id\";s:11:\"flat_rate:1\";s:9:\"method_id\";s:9:\"flat_rate\";s:11:\"instance_id\";i:1;s:5:\"label\";s:9:\"Flat rate\";s:4:\"cost\";s:4:\"0.00\";s:5:\"taxes\";a:0:{}}s:12:\"\0*\0meta_data\";a:1:{s:5:\"Items\";s:26:\"Hoodie with Logo × 1\";}}}}\";s:25:\"previous_shipping_methods\";s:39:\"a:1:{i:0;a:1:{i:0;s:11:\"flat_rate:1\";}}\";s:23:\"chosen_shipping_methods\";s:29:\"a:1:{i:0;s:11:\"flat_rate:1\";}\";s:22:\"shipping_method_counts\";s:14:\"a:1:{i:0;i:1;}\";}',1528977164); -/*!40000 ALTER TABLE `wp_woocommerce_sessions` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_shipping_zone_locations` --- - -DROP TABLE IF EXISTS `wp_woocommerce_shipping_zone_locations`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_shipping_zone_locations` ( - `location_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `zone_id` bigint(20) unsigned NOT NULL, - `location_code` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, - `location_type` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL, - PRIMARY KEY (`location_id`), - KEY `location_id` (`location_id`), - KEY `location_type_code` (`location_type`(10),`location_code`(20)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_shipping_zone_locations` --- - -LOCK TABLES `wp_woocommerce_shipping_zone_locations` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_shipping_zone_locations` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_woocommerce_shipping_zone_locations` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_shipping_zone_methods` --- - -DROP TABLE IF EXISTS `wp_woocommerce_shipping_zone_methods`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_shipping_zone_methods` ( - `zone_id` bigint(20) unsigned NOT NULL, - `instance_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `method_id` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, - `method_order` bigint(20) unsigned NOT NULL, - `is_enabled` tinyint(1) NOT NULL DEFAULT 1, - PRIMARY KEY (`instance_id`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_shipping_zone_methods` --- - -LOCK TABLES `wp_woocommerce_shipping_zone_methods` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_shipping_zone_methods` DISABLE KEYS */; -INSERT INTO `wp_woocommerce_shipping_zone_methods` VALUES (0,1,'flat_rate',1,1); -/*!40000 ALTER TABLE `wp_woocommerce_shipping_zone_methods` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_shipping_zones` --- - -DROP TABLE IF EXISTS `wp_woocommerce_shipping_zones`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_shipping_zones` ( - `zone_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `zone_name` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, - `zone_order` bigint(20) unsigned NOT NULL, - PRIMARY KEY (`zone_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_shipping_zones` --- - -LOCK TABLES `wp_woocommerce_shipping_zones` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_shipping_zones` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_woocommerce_shipping_zones` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_tax_rate_locations` --- - -DROP TABLE IF EXISTS `wp_woocommerce_tax_rate_locations`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_tax_rate_locations` ( - `location_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `location_code` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, - `tax_rate_id` bigint(20) unsigned NOT NULL, - `location_type` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL, - PRIMARY KEY (`location_id`), - KEY `tax_rate_id` (`tax_rate_id`), - KEY `location_type_code` (`location_type`(10),`location_code`(20)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_tax_rate_locations` --- - -LOCK TABLES `wp_woocommerce_tax_rate_locations` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_tax_rate_locations` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_woocommerce_tax_rate_locations` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `wp_woocommerce_tax_rates` --- - -DROP TABLE IF EXISTS `wp_woocommerce_tax_rates`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `wp_woocommerce_tax_rates` ( - `tax_rate_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `tax_rate_country` varchar(2) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `tax_rate_state` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `tax_rate` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `tax_rate_name` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `tax_rate_priority` bigint(20) unsigned NOT NULL, - `tax_rate_compound` int(1) NOT NULL DEFAULT 0, - `tax_rate_shipping` int(1) NOT NULL DEFAULT 1, - `tax_rate_order` bigint(20) unsigned NOT NULL, - `tax_rate_class` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - PRIMARY KEY (`tax_rate_id`), - KEY `tax_rate_country` (`tax_rate_country`), - KEY `tax_rate_state` (`tax_rate_state`(2)), - KEY `tax_rate_class` (`tax_rate_class`(10)), - KEY `tax_rate_priority` (`tax_rate_priority`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `wp_woocommerce_tax_rates` --- - -LOCK TABLES `wp_woocommerce_tax_rates` WRITE; -/*!40000 ALTER TABLE `wp_woocommerce_tax_rates` DISABLE KEYS */; -/*!40000 ALTER TABLE `wp_woocommerce_tax_rates` ENABLE KEYS */; -UNLOCK TABLES; -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - --- Dump completed on 2018-12-19 12:54:11 diff --git a/tests/e2e-tests/front-end/cart-page.js b/tests/e2e-tests/front-end/cart-page.js deleted file mode 100644 index a0fd6cb1436..00000000000 --- a/tests/e2e-tests/front-end/cart-page.js +++ /dev/null @@ -1,118 +0,0 @@ -import config from 'config'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import test from 'selenium-webdriver/testing'; -import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; -import { ShopPage, CartPage } from 'wc-e2e-page-objects'; - -chai.use( chaiAsPromised ); -const assert = chai.assert; - -let manager; -let driver; - -test.describe( 'Cart page', function() { - // open browser - test.before( function() { - this.timeout( config.get( 'startBrowserTimeoutMs' ) ); - - manager = new WebDriverManager( 'chrome', { baseUrl: config.get( 'url' ) } ); - driver = manager.getDriver(); - - helper.clearCookiesAndDeleteLocalStorage( driver ); - } ); - - this.timeout( config.get( 'mochaTimeoutMs' ) ); - - test.it( 'should displays no item in the cart', () => { - const cartPage = new CartPage( driver, { url: manager.getPageUrl( '/cart' ) } ); - assert.eventually.equal( cartPage.hasNoItem(), true ); - } ); - - test.it( 'should adds the product to the cart when "Add to cart" is clicked', () => { - const shopPage = new ShopPage( driver, { url: manager.getPageUrl( '/shop' ) } ); - assert.eventually.equal( shopPage.addProductToCart( 'Album' ), true ); - assert.eventually.equal( shopPage.addProductToCart( 'Polo' ), true ); - - const cartPage = new CartPage( driver, { url: manager.getPageUrl( '/cart' ) } ); - assert.eventually.equal( cartPage.hasItem( 'Album' ), true ); - assert.eventually.equal( cartPage.hasItem( 'Polo' ), true ); - } ); - - test.it( 'should increases item qty when "Add to cart" of the same product is clicked', () => { - const shopPage = new ShopPage( driver, { url: manager.getPageUrl( '/shop' ) } ); - assert.eventually.equal( shopPage.addProductToCart( 'Album' ), true ); - - const cartPage = new CartPage( driver, { url: manager.getPageUrl( '/cart' ) } ); - assert.eventually.equal( cartPage.hasItem( 'Album', { qty: 2 } ), true ); - assert.eventually.equal( cartPage.hasItem( 'Polo', { qty: 1 } ), true ); - } ); - - test.it( 'should updates qty when updated via qty input', () => { - const cartPage = new CartPage( driver, { url: manager.getPageUrl( '/cart' ) } ); - cartPage.getItem( 'Album', { qty: 2 } ).setQty( 4 ); - cartPage.getItem( 'Polo', { qty: 1 } ).setQty( 3 ); - cartPage.update(); - - assert.eventually.equal( cartPage.hasItem( 'Album', { qty: 4 } ), true ); - assert.eventually.equal( cartPage.hasItem( 'Polo', { qty: 3 } ), true ); - } ); - - test.it( 'should remove the item from the cart when remove is clicked', () => { - const cartPage = new CartPage( driver, { url: manager.getPageUrl( '/cart' ) } ); - cartPage.getItem( 'Album', { qty: 4 } ).remove(); - cartPage.getItem( 'Polo', { qty: 3 } ).remove(); - - assert.eventually.equal( cartPage.hasNoItem(), true ); - } ); - - test.it( 'should update subtotal in cart totals when adding product to the cart', () => { - const shopPage = new ShopPage( driver, { url: manager.getPageUrl( '/shop' ) } ); - assert.eventually.equal( shopPage.addProductToCart( 'Album' ), true ); - - const cartPage = new CartPage( driver, { url: manager.getPageUrl( '/cart' ) } ); - assert.eventually.equal( - cartPage.hasItem( 'Album', { qty: 1 } ), - true, - 'Cart item "Album" with qty 1 is not displayed' - ); - - assert.eventually.equal( - cartPage.hasSubtotal( '15.00' ), - true, - 'Cart totals does not display subtotal of 15.00' - ); - - cartPage.getItem( 'Album', { qty: 1 } ).setQty( 2 ); - cartPage.update(); - - assert.eventually.equal( - cartPage.hasSubtotal( '30.00' ), - true, - 'Cart totals does not display subtotal of 30.00' - ); - } ); - - test.it( 'should go to the checkout page when "Proceed to Checkout" is clicked', () => { - const cartPage = new CartPage( driver, { url: manager.getPageUrl( '/cart' ) } ); - const checkoutPage = cartPage.checkout(); - - assert.eventually.equal( - checkoutPage.components.orderReview.displayed(), - true, - 'Order review in checkout page is not displayed' - ); - } ); - - // take screenshot - test.afterEach( function() { - if ( this.currentTest.state === 'failed' ) { - helper.takeScreenshot( manager, this.currentTest ); - } - } ); - - // quit browser - test.after( () => { - manager.quitBrowser(); - } ); -} ); diff --git a/tests/e2e-tests/front-end/checkout-page.js b/tests/e2e-tests/front-end/checkout-page.js deleted file mode 100644 index 347a4973434..00000000000 --- a/tests/e2e-tests/front-end/checkout-page.js +++ /dev/null @@ -1,162 +0,0 @@ -import config from 'config'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import test from 'selenium-webdriver/testing'; -import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; -import { Helper, PageMap, CheckoutOrderReceivedPage, StoreOwnerFlow, GuestCustomerFlow } from 'wc-e2e-page-objects'; - -chai.use( chaiAsPromised ); - -const assert = chai.assert; -const PAGE = PageMap.PAGE; -const storeOwnerFlowArgs = { - baseUrl: config.get( 'url' ), - username: config.get( 'users.admin.username' ), - password: config.get( 'users.admin.password' ) -}; - -const assertOrderItem = ( orderReview, itemName, attrs ) => { - assert.eventually.ok( - orderReview.hasItem( itemName, attrs ), - `Could not find order item "${ itemName }" with qty ${ attrs.qty } and total ${ attrs.total }` - ); -}; - -let manager; -let driver; - -test.describe( 'Checkout Page', function() { - // open browser - test.before( function() { - this.timeout( config.get( 'startBrowserTimeoutMs' ) ); - - manager = new WebDriverManager( 'chrome', { baseUrl: config.get( 'url' ) } ); - driver = manager.getDriver(); - - helper.clearCookiesAndDeleteLocalStorage( driver ); - - const storeOwner = new StoreOwnerFlow( driver, storeOwnerFlowArgs ); - - // General settings for this test. - storeOwner.setGeneralSettings( { - baseLocation: [ 'United States', 'United States (US) — California' ], - sellingLocation: 'Sell to all countries', - enableTaxes: true, - currency: [ 'United States', 'United States (US) dollar ($)' ], - } ); - - // Make sure payment method is set in setting. - storeOwner.enableBACS(); - storeOwner.enableCOD(); - storeOwner.enablePayPal(); - - storeOwner.logout(); - } ); - - this.timeout( config.get( 'mochaTimeoutMs' ) ); - - test.it( 'should displays cart items in order review', () => { - const guest = new GuestCustomerFlow( driver, { baseUrl: config.get( 'url' ) } ); - guest.fromShopAddProductsToCart( 'Beanie', 'Long Sleeve Tee' ); - - const checkoutPage = guest.openCheckout(); - assert.eventually.ok( Helper.waitTillUIBlockNotPresent( driver ) ); - - const orderReview = checkoutPage.components.orderReview; - assertOrderItem( orderReview, 'Beanie', { qty: '1', total: '18.00' } ); - assertOrderItem( orderReview, 'Long Sleeve Tee', { qty: '1', total: '25.00' } ); - assert.eventually.ok( orderReview.hasSubtotal( '43.00' ), 'Could not find subtotal 43.00' ); - } ); - - test.it( 'allows customer to choose available payment methods', () => { - const guest = new GuestCustomerFlow( driver, { baseUrl: config.get( 'url' ) } ); - guest.fromShopAddProductsToCart( 'Beanie', 'Long Sleeve Tee' ); - - const checkoutPage = guest.openCheckout(); - assert.eventually.ok( Helper.waitTillUIBlockNotPresent( driver ) ); - assert.eventually.ok( checkoutPage.selectPaymentMethod( 'PayPal' ) ); - assert.eventually.ok( checkoutPage.selectPaymentMethod( 'Direct bank transfer' ) ); - assert.eventually.ok( checkoutPage.selectPaymentMethod( 'Cash on delivery' ) ); - } ); - - test.it( 'allows customer to fill billing details', () => { - const guest = new GuestCustomerFlow( driver, { baseUrl: config.get( 'url' ) } ); - guest.fromShopAddProductsToCart( 'Beanie', 'Long Sleeve Tee' ); - - const checkoutPage = guest.open( PAGE.CHECKOUT ); - assert.eventually.ok( Helper.waitTillUIBlockNotPresent( driver ) ); - - const billingDetails = checkoutPage.components.billingDetails; - assert.eventually.ok( billingDetails.setFirstName( 'John' ) ); - assert.eventually.ok( billingDetails.setLastName( 'Doe' ) ); - assert.eventually.ok( billingDetails.setCompany( 'Automattic' ) ); - assert.eventually.ok( billingDetails.setEmail( 'john.doe@example.com' ) ); - assert.eventually.ok( billingDetails.setPhone( '123456789' ) ); - assert.eventually.ok( billingDetails.selectCountry( 'united states', 'United States (US)' ) ); - assert.eventually.ok( billingDetails.setAddress1( 'addr 1' ) ); - assert.eventually.ok( billingDetails.setAddress2( 'addr 2' ) ); - assert.eventually.ok( billingDetails.setCity( 'San Francisco' ) ); - assert.eventually.ok( billingDetails.selectState( 'cali', 'California' ) ); - assert.eventually.ok( billingDetails.setZip( '94107' ) ); - } ); - - test.it( 'allows customer to fill shipping details', () => { - const guest = new GuestCustomerFlow( driver, { baseUrl: config.get( 'url' ) } ); - guest.fromShopAddProductsToCart( 'Beanie', 'Long Sleeve Tee' ); - - const checkoutPage = guest.open( PAGE.CHECKOUT ); - assert.eventually.ok( Helper.waitTillUIBlockNotPresent( driver ) ); - assert.eventually.ok( checkoutPage.checkShipToDifferentAddress() ); - - const shippingDetails = checkoutPage.components.shippingDetails; - assert.eventually.ok( shippingDetails.setFirstName( 'John' ) ); - assert.eventually.ok( shippingDetails.setLastName( 'Doe' ) ); - assert.eventually.ok( shippingDetails.setCompany( 'Automattic' ) ); - assert.eventually.ok( shippingDetails.selectCountry( 'united states', 'United States (US)' ) ); - assert.eventually.ok( shippingDetails.setAddress1( 'addr 1' ) ); - assert.eventually.ok( shippingDetails.setAddress2( 'addr 2' ) ); - assert.eventually.ok( shippingDetails.setCity( 'San Francisco' ) ); - assert.eventually.ok( shippingDetails.selectState( 'cali', 'California' ) ); - assert.eventually.ok( shippingDetails.setZip( '94107' ) ); - } ); - - test.it( 'allows guest customer to place order', () => { - const guest = new GuestCustomerFlow( driver, { baseUrl: config.get( 'url' ) } ); - guest.fromShopAddProductsToCart( 'Beanie', 'Long Sleeve Tee' ); - - const checkoutPage = guest.open( PAGE.CHECKOUT ); - const billingDetails = checkoutPage.components.billingDetails; - Helper.waitTillUIBlockNotPresent( driver ); - billingDetails.setFirstName( 'John' ); - billingDetails.setLastName( 'Doe' ); - billingDetails.setCompany( 'Automattic' ); - billingDetails.setEmail( 'john.doe@example.com' ); - billingDetails.setPhone( '123456789' ); - billingDetails.selectCountry( 'united states', 'United States (US)' ); - billingDetails.setAddress1( 'addr 1' ); - billingDetails.setAddress2( 'addr 2' ); - billingDetails.setCity( 'San Francisco' ); - billingDetails.selectState( 'cali', 'California' ); - billingDetails.setZip( '94107' ); - Helper.waitTillUIBlockNotPresent( driver ); - checkoutPage.selectPaymentMethod( 'Cash on delivery' ); - checkoutPage.placeOrder(); - Helper.waitTillUIBlockNotPresent( driver ); - - assert.eventually.ok( - checkoutPage.hasText( 'Order received' ) - ); - } ); - - // take screenshot - test.afterEach( function() { - if ( this.currentTest.state === 'failed' ) { - helper.takeScreenshot( manager, this.currentTest ); - } - } ); - - // quit browser - test.after( () => { - manager.quitBrowser(); - } ); -} ); diff --git a/tests/e2e-tests/front-end/my-account-page.js b/tests/e2e-tests/front-end/my-account-page.js deleted file mode 100644 index 81d6de60f4d..00000000000 --- a/tests/e2e-tests/front-end/my-account-page.js +++ /dev/null @@ -1,129 +0,0 @@ -/** - * External dependencies - */ -import config from 'config'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import test from 'selenium-webdriver/testing'; -import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; -import { CustomerFlow, MyAccountPage, PageMap } from 'wc-e2e-page-objects'; - -chai.use( chaiAsPromised ); -const assert = chai.assert; - -let manager; -let driver; - -test.describe( 'My account page', function() { - const loginAsCustomer = () => { - return new CustomerFlow( driver, { - baseUrl: config.get( 'url' ), - username: config.get( 'users.customer.username' ), - password: config.get( 'users.customer.password' ) - } ); - }; - const getMyAccountSubPageUrl = path => { - return PageMap.getPageUrl( config.get( 'url' ), { - path: '/my-account/%s' - }, path ); - }; - const untrailingslashit = url => { - return url.endsWith( '/' ) ? url.substring( 0, url.length - 1 ) : url; - }; - - // open browser - test.before( function() { - this.timeout( config.get( 'startBrowserTimeoutMs' ) ); - - manager = new WebDriverManager( 'chrome', { baseUrl: config.get( 'url' ) } ); - driver = manager.getDriver(); - - helper.clearCookiesAndDeleteLocalStorage( driver ); - } ); - - this.timeout( config.get( 'mochaTimeoutMs' ) ); - - test.it( 'allows customer to login', () => { - loginAsCustomer(); - const myAccount = new MyAccountPage( driver, { - baseUrl: config.get( 'url' ), - visit: false - } ); - - assert.eventually.ok( myAccount.hasText( 'Hello Customer' ), 'see "Hello Customer" text' ); - assert.eventually.ok( myAccount.hasMenu( 'Dashboard' ), 'see Dashboard menu.' ); - assert.eventually.ok( myAccount.hasMenu( 'Orders' ), 'see Orders menu' ); - } ); - - test.it( 'allows customer to see orders', () => { - loginAsCustomer(); - const myAccount = new MyAccountPage( driver, { - baseUrl: config.get( 'url' ), - visit: false - } ); - myAccount.clickMenu( 'Orders' ); - - assert.eventually.equal( - driver.getCurrentUrl().then( untrailingslashit ), - untrailingslashit( getMyAccountSubPageUrl( 'orders' ) ) - ); - assert.eventually.ok( myAccount.hasText( 'Orders' ), 'see "Orders" text' ); - } ); - - test.it( 'allows customer to see downloads', () => { - loginAsCustomer(); - const myAccount = new MyAccountPage( driver, { - baseUrl: config.get( 'url' ), - visit: false - } ); - myAccount.clickMenu( 'Downloads' ); - - assert.eventually.equal( - driver.getCurrentUrl().then( untrailingslashit ), - untrailingslashit( getMyAccountSubPageUrl( 'downloads' ) ) - ); - assert.eventually.ok( myAccount.hasText( 'Downloads' ), 'see "Downloads" text' ); - } ); - - test.it( 'allows customer to edit addresses', () => { - loginAsCustomer(); - const myAccount = new MyAccountPage( driver, { - baseUrl: config.get( 'url' ), - visit: false - } ); - myAccount.clickMenu( 'Addresses' ); - - assert.eventually.equal( - driver.getCurrentUrl().then( untrailingslashit ), - untrailingslashit( getMyAccountSubPageUrl( 'edit-address' ) ) - ); - assert.eventually.ok( myAccount.hasText( 'Addresses' ), 'see "Addresses" text' ); - } ); - - test.it( 'allows customer to edit account details', () => { - loginAsCustomer(); - const myAccount = new MyAccountPage( driver, { - baseUrl: config.get( 'url' ), - visit: false - } ); - myAccount.clickMenu( 'Account details' ); - - assert.eventually.equal( - driver.getCurrentUrl().then( untrailingslashit ), - untrailingslashit( getMyAccountSubPageUrl( 'edit-account' ) ) - ); - assert.eventually.ok( myAccount.hasText( 'Account details' ), 'see "Account details" text' ); - } ); - - // take screenshot - test.afterEach( function() { - if ( this.currentTest.state === 'failed' ) { - helper.takeScreenshot( manager, this.currentTest ); - } - } ); - - // quit browser - test.after( () => { - manager.quitBrowser(); - } ); -} ); diff --git a/tests/e2e-tests/front-end/single-product.js b/tests/e2e-tests/front-end/single-product.js deleted file mode 100644 index e7170fc86aa..00000000000 --- a/tests/e2e-tests/front-end/single-product.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * External dependencies - */ -import config from 'config'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import test from 'selenium-webdriver/testing'; -import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; -import { SingleProductPage, CartPage } from 'wc-e2e-page-objects'; - -chai.use( chaiAsPromised ); - -const assert = chai.assert; - -let manager; -let driver; - -test.describe( 'Single Product Page', function() { - const visitProductByPath = path => { - return new SingleProductPage( driver, { url: manager.getPageUrl( path ) } ); - }; - const visitCart = () => { - return new CartPage( driver, { url: manager.getPageUrl( '/cart' ) } ); - }; - - // open browser - test.before( function() { - this.timeout( config.get( 'startBrowserTimeoutMs' ) ); - - manager = new WebDriverManager( 'chrome', { baseUrl: config.get( 'url' ) } ); - driver = manager.getDriver(); - - helper.clearCookiesAndDeleteLocalStorage( driver ); - } ); - - this.timeout( config.get( 'mochaTimeoutMs' ) ); - - test.it( 'should be able to add simple products to the cart', () => { - const productPage = visitProductByPath( '/product/t-shirt' ); - productPage.setQuantity( 5 ); - productPage.addToCart(); - - assert.eventually.equal( visitCart().hasItem( 'T-Shirt', { qty: 5 } ), true ); - } ); - - test.it( 'should be able to add variation products to the cart', () => { - let variableProductPage; - - variableProductPage = visitProductByPath( '/product/hoodie' ); - variableProductPage.selectVariation( 'Color', 'Blue' ); - variableProductPage.selectVariation( 'Logo', 'Yes' ); - driver.sleep( 500 ); - variableProductPage.addToCart(); - assert.eventually.ok( visitCart().hasItem( 'Hoodie - Blue, Yes' ), '"Hoodie - Blue, Yes" in the cart' ); - - variableProductPage = visitProductByPath( '/product/hoodie' ); - variableProductPage.selectVariation( 'Color', 'Green' ); - variableProductPage.selectVariation( 'Logo', 'No' ); - driver.sleep( 500 ); - variableProductPage.addToCart(); - assert.eventually.ok( visitCart().hasItem( 'Hoodie - Green, No' ), '"Hoodie - Green, No" in the cart' ); - } ); - - // take screenshot - test.afterEach( function() { - if ( this.currentTest.state === 'failed' ) { - helper.takeScreenshot( manager, this.currentTest ); - } - } ); - - // quit browser - test.after( () => { - manager.quitBrowser(); - } ); -} ); diff --git a/tests/e2e-tests/specs/activate-and-setup/setup-wizard.test.js b/tests/e2e-tests/specs/activate-and-setup/setup-wizard.test.js new file mode 100644 index 00000000000..fff10414d8d --- /dev/null +++ b/tests/e2e-tests/specs/activate-and-setup/setup-wizard.test.js @@ -0,0 +1,116 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { StoreOwnerFlow } from '../../utils/flows'; +import { completeOldSetupWizard } from '../../utils/components'; +import { + permalinkSettingsPageSaveChanges, + setCheckbox, + settingsPageSaveChanges, + verifyCheckboxIsSet, + verifyCheckboxIsUnset, verifyValueOfInputField +} from '../../utils'; + +const config = require( 'config' ); + +describe( 'Store owner can login and make sure WooCommerce is activated', () => { + + it( 'can login', async () => { + await StoreOwnerFlow.login(); + } ); + + it( 'can make sure WooCommerce is activated. If not, activate it', async () => { + const slug = 'woocommerce'; + await StoreOwnerFlow.openPlugins(); + const disableLink = await page.$( `tr[data-slug="${ slug }"] .deactivate a` ); + if ( disableLink ) { + return; + } + await page.click( `tr[data-slug="${ slug }"] .activate a` ); + await page.waitForSelector( `tr[data-slug="${ slug }"] .deactivate a` ); + } ); + +} ); + +describe( 'Store owner can go through store Setup Wizard', () => { + + it( 'can start Setup Wizard when visiting the site for the first time. Skip all other times.', async () => { + // Check if Setup Wizard Notice is visible on the screen. + // If yes - proceed with Setup Wizard, if not - skip Setup Wizard (already been completed). + const setupWizardNotice = await Promise.race( [ + new Promise( resolve => setTimeout( () => resolve(), 1000 ) ), // resolves without value after 1s + page.waitForSelector('.updated.woocommerce-message.wc-connect', { visible: true } ) + ] ); + if ( setupWizardNotice ) { + await StoreOwnerFlow.runSetupWizard(); + + // Check if the New Setup Wizard Notice (since 3.9) is visible on the screen. + // If yes - continue with the old Setup Wizard. + // If not - the test will continue with the old wizard by default. + const newSetupWizardNotice = await Promise.race( [ + new Promise( resolve => setTimeout( () => resolve(), 1000) ), // resolves without value after 1s + page.waitForSelector( '.wc-setup-step__new_onboarding-wrapper', { visible: true } ) + ] ); + if ( newSetupWizardNotice ) { + // Continue with the old setup wizard + await Promise.all( [ + // Click on "Continue with the old setup wizard" footer link to start the old setup wizard + page.$eval( '.wc-setup-footer-links', elem => elem.click() ), + + // Wait for the store setup section to load + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ] ); + } + await completeOldSetupWizard(); + } + } ); +} ); + +describe( 'Store owner can finish initial store setup', () => { + + it( 'can enable tax rates and calculations', async () => { + // Go to general settings page + await StoreOwnerFlow.openSettings( 'general' ); + + // Make sure the general tab is active + await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'General' } ); + + // Enable tax rates and calculations + await setCheckbox( '#woocommerce_calc_taxes' ); + + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + verifyCheckboxIsSet( '#woocommerce_calc_taxes' ), + ] ); + } ); + + it( 'can configure permalink settings', async () => { + // Go to Permalink Settings page + await StoreOwnerFlow.openPermalinkSettings(); + + // Select "Post name" option in common settings section + await page.click( 'input[value="/%postname%/"]', { text: ' Post name' } ); + + // Select "Custom base" in product permalinks section + await page.click( '#woocommerce_custom_selection' ); + + // Fill custom base slug to use + await expect( page ).toFill( '#woocommerce_permalink_structure', '/product/' ); + + await permalinkSettingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#setting-error-settings_updated', { text: 'Permalink structure updated.' } ), + verifyValueOfInputField( '#permalink_structure', '/%postname%/' ), + verifyValueOfInputField( '#woocommerce_permalink_structure', '/product/' ), + ] ); + } ); +} ); diff --git a/tests/e2e-tests/specs/front-end/front-end-cart.test.js b/tests/e2e-tests/specs/front-end/front-end-cart.test.js new file mode 100644 index 00000000000..8d8e3c802da --- /dev/null +++ b/tests/e2e-tests/specs/front-end/front-end-cart.test.js @@ -0,0 +1,81 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { createSimpleProduct } from '../../utils/components'; +import { CustomerFlow, StoreOwnerFlow } from '../../utils/flows'; +import { uiUnblocked } from '../../utils'; + +describe( 'Cart page', () => { + beforeAll( async () => { + await StoreOwnerFlow.login(); + await createSimpleProduct(); + await StoreOwnerFlow.logout(); + } ); + + it( 'should display no item in the cart', async () => { + await CustomerFlow.goToCart(); + await expect( page ).toMatchElement( '.cart-empty', { text: 'Your cart is currently empty.' } ); + } ); + + it( 'should add the product to the cart when "Add to cart" is clicked', async () => { + await CustomerFlow.goToShop(); + await CustomerFlow.addToCartFromShopPage( 'Simple product' ); + + await CustomerFlow.goToCart(); + await CustomerFlow.productIsInCart( 'Simple product' ); + } ); + + it( 'should increase item qty when "Add to cart" of the same product is clicked', async () => { + await CustomerFlow.goToShop(); + await CustomerFlow.addToCartFromShopPage( 'Simple product' ); + + await CustomerFlow.goToCart(); + await CustomerFlow.productIsInCart( 'Simple product', 2 ); + } ); + + it( 'should update qty when updated via qty input', async () => { + await CustomerFlow.goToCart(); + await CustomerFlow.setCartQuantity( 'Simple product', 4 ); + await expect( page ).toClick( 'button', { text: 'Update cart' } ); + await uiUnblocked(); + + await CustomerFlow.productIsInCart( 'Simple product', 4 ); + } ); + + it( 'should remove the item from the cart when remove is clicked', async () => { + await CustomerFlow.goToCart(); + await CustomerFlow.removeFromCart( 'Simple product' ); + await uiUnblocked(); + + await expect( page ).toMatchElement( '.cart-empty', { text: 'Your cart is currently empty.' } ); + } ); + + it( 'should update subtotal in cart totals when adding product to the cart', async () => { + await CustomerFlow.goToShop(); + await CustomerFlow.addToCartFromShopPage( 'Simple product' ); + + await CustomerFlow.goToCart(); + await CustomerFlow.productIsInCart( 'Simple product', 1 ); + await expect( page ).toMatchElement( '.cart-subtotal .amount', { text: '$9.99' } ); + + await CustomerFlow.setCartQuantity( 'Simple product', 2 ); + await expect( page ).toClick( 'button', { text: 'Update cart' } ); + await uiUnblocked(); + + await expect( page ).toMatchElement( '.cart-subtotal .amount', { text: '$19.98' } ); + } ); + + it( 'should go to the checkout page when "Proceed to Checkout" is clicked', async () => { + await CustomerFlow.goToCart(); + await Promise.all( [ + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + expect( page ).toClick( '.checkout-button', { text: 'Proceed to checkout' } ), + ] ); + + await expect( page ).toMatchElement( '#order_review' ); + } ); +} ); diff --git a/tests/e2e-tests/specs/front-end/front-end-checkout.test.js b/tests/e2e-tests/specs/front-end/front-end-checkout.test.js new file mode 100644 index 00000000000..3285cc377b0 --- /dev/null +++ b/tests/e2e-tests/specs/front-end/front-end-checkout.test.js @@ -0,0 +1,158 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { createSimpleProduct } from '../../utils/components'; +import { CustomerFlow, StoreOwnerFlow } from '../../utils/flows'; +import { setCheckbox, settingsPageSaveChanges, uiUnblocked, verifyCheckboxIsSet } from '../../utils'; + +const config = require( 'config' ); +const simpleProductName = config.get( 'products.simple.name' ); +let orderId; + +describe( 'Checkout page', () => { + beforeAll( async () => { + await StoreOwnerFlow.login(); + await createSimpleProduct(); + + // Go to general settings page + await StoreOwnerFlow.openSettings( 'general' ); + + // Set base location with state CA. + await expect( page ).toSelect( 'select[name="woocommerce_default_country"]', 'United States (US) — California' ); + // Sell to all countries + await expect( page ).toSelect( '#woocommerce_allowed_countries', 'Sell to all countries' ); + // Set currency to USD + await expect( page ).toSelect( '#woocommerce_currency', 'United States (US) dollar ($)' ); + // Tax calculation should have been enabled by another test - no-op + // Save + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + expect( page ).toMatchElement( 'select[name="woocommerce_default_country"]', { text: 'United States (US) — California' } ), + expect( page ).toMatchElement( '#woocommerce_allowed_countries', { text: 'Sell to all countries' } ), + expect( page ).toMatchElement( '#woocommerce_currency', { text: 'United States (US) dollar ($)' } ), + ] ); + + // Enable BACS payment method + await StoreOwnerFlow.openSettings( 'checkout', 'bacs' ); + await setCheckbox( '#woocommerce_bacs_enabled' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await verifyCheckboxIsSet( '#woocommerce_bacs_enabled' ); + + // Enable COD payment method + await StoreOwnerFlow.openSettings( 'checkout', 'cod' ); + await setCheckbox( '#woocommerce_cod_enabled' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await verifyCheckboxIsSet( '#woocommerce_cod_enabled' ); + + // Enable PayPal payment method + await StoreOwnerFlow.openSettings( 'checkout', 'paypal' ); + await setCheckbox( '#woocommerce_paypal_enabled' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await verifyCheckboxIsSet( '#woocommerce_paypal_enabled' ); + + await StoreOwnerFlow.logout(); + } ); + + it( 'should display cart items in order review', async () => { + await CustomerFlow.goToShop(); + await CustomerFlow.addToCartFromShopPage( simpleProductName ); + await CustomerFlow.goToCheckout(); + await CustomerFlow.productIsInCheckout( simpleProductName, `1`, `9.99`, `9.99` ); + } ); + + it( 'allows customer to choose available payment methods', async () => { + await CustomerFlow.goToShop(); + await CustomerFlow.addToCartFromShopPage( simpleProductName ); + await CustomerFlow.goToCheckout(); + await CustomerFlow.productIsInCheckout( simpleProductName, `2`, `19.98`, `19.98` ); + + await expect( page ).toClick( '.wc_payment_method label', { text: 'PayPal' } ); + await expect( page ).toClick( '.wc_payment_method label', { text: 'Direct bank transfer' } ); + await expect( page ).toClick( '.wc_payment_method label', { text: 'Cash on delivery' } ); + } ); + + it( 'allows customer to fill billing details', async () => { + await CustomerFlow.goToShop(); + await CustomerFlow.addToCartFromShopPage( simpleProductName ); + await CustomerFlow.goToCheckout(); + await CustomerFlow.productIsInCheckout( simpleProductName, `3`, `29.97`, `29.97` ); + await CustomerFlow.fillBillingDetails( config.get( 'addresses.customer.billing' ) ); + } ); + + it( 'allows customer to fill shipping details', async () => { + await CustomerFlow.goToShop(); + await CustomerFlow.addToCartFromShopPage( simpleProductName ); + await CustomerFlow.goToCheckout(); + await CustomerFlow.productIsInCheckout( simpleProductName, `4`, `39.96`, `39.96` ); + + // Select checkbox to ship to a different address + await page.evaluate( () => { + document.querySelector( '#ship-to-different-address-checkbox' ).click(); + } ); + await uiUnblocked(); + + await CustomerFlow.fillShippingDetails( config.get( 'addresses.customer.shipping' ) ); + } ); + + it( 'allows guest customer to place order', async () => { + await CustomerFlow.goToShop(); + await CustomerFlow.addToCartFromShopPage( simpleProductName ); + await CustomerFlow.goToCheckout(); + await CustomerFlow.productIsInCheckout( simpleProductName, `5`, `49.95`, `49.95` ); + await CustomerFlow.fillBillingDetails( config.get( 'addresses.customer.billing' ) ); + + await uiUnblocked(); + + await expect( page ).toClick( '.wc_payment_method label', { text: 'Cash on delivery' } ); + await expect( page ).toMatchElement( '.payment_method_cod', { text: 'Pay with cash upon delivery.' } ); + await uiUnblocked(); + await CustomerFlow.placeOrder(); + + await expect( page ).toMatch( 'Order received' ); + + // Get order ID from the order received html element on the page + let orderReceivedHtmlElement = await page.$( '.woocommerce-order-overview__order.order' ); + let orderReceivedText = await page.evaluate( element => element.textContent, orderReceivedHtmlElement ); + return orderId = orderReceivedText.split( /(\s+)/ )[6].toString(); + } ); + + it( 'store owner can confirm the order was received', async () => { + await StoreOwnerFlow.login(); + await StoreOwnerFlow.openAllOrdersView(); + + // Click on the order which was placed in the previous step + await Promise.all( [ + page.click( '#post-' + orderId ), + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ] ); + + // Verify that the order page is indeed of the order that was placed + // Verify order number + await expect( page ).toMatchElement( '.woocommerce-order-data__heading', { text: 'Order #' + orderId + ' details' } ); + + // Verify product name + await expect( page ).toMatchElement( '.wc-order-item-name', { text: simpleProductName } ); + + // Verify product cost + await expect( page ).toMatchElement( '.woocommerce-Price-amount.amount', { text: '9.99' } ); + + // Verify product quantity + await expect( page ).toMatchElement( '.quantity', { text: '5' } ); + + // Verify total order amount without shipping + await expect( page ).toMatchElement( '.line_cost', { text: '49.95' } ); + } ); +} ); diff --git a/tests/e2e-tests/specs/front-end/front-end-my-account.test.js b/tests/e2e-tests/specs/front-end/front-end-my-account.test.js new file mode 100644 index 00000000000..86a9f0c22d5 --- /dev/null +++ b/tests/e2e-tests/specs/front-end/front-end-my-account.test.js @@ -0,0 +1,46 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { CustomerFlow, StoreOwnerFlow } from '../../utils/flows'; + +describe( 'My account page', () => { + it( 'allows customer to login', async () => { + await StoreOwnerFlow.logout(); + await CustomerFlow.login(); + await expect( page ).toMatch( 'Hello' ); + await expect( page ).toMatchElement( '.woocommerce-MyAccount-navigation-link', { text: 'Dashboard' } ); + await expect( page ).toMatchElement( '.woocommerce-MyAccount-navigation-link', { text: 'Orders' } ); + await expect( page ).toMatchElement( '.woocommerce-MyAccount-navigation-link', { text: 'Downloads' } ); + await expect( page ).toMatchElement( '.woocommerce-MyAccount-navigation-link', { text: 'Addresses' } ); + await expect( page ).toMatchElement( '.woocommerce-MyAccount-navigation-link', { text: 'Account details' } ); + await expect( page ).toMatchElement( '.woocommerce-MyAccount-navigation-link', { text: 'Logout' } ); + } ); + + it( 'allows customer to see orders', async () => { + await CustomerFlow.goToOrders(); + await expect( page.url() ).toMatch( 'my-account/orders' ); + await expect( page ).toMatchElement( 'h1', { text: 'Orders' } ); + } ); + + it( 'allows customer to see downloads', async () => { + await CustomerFlow.goToDownloads(); + expect( page.url() ).toMatch( 'my-account/downloads' ); + await expect( page ).toMatchElement( 'h1', { text: 'Downloads' } ); + } ); + + it( 'allows customer to see addresses', async () => { + await CustomerFlow.goToAddresses(); + expect( page.url() ).toMatch( 'my-account/edit-address' ); + await expect( page ).toMatchElement( 'h1', { text: 'Addresses' } ); + } ); + + it( 'allows customer to see account details', async () => { + await CustomerFlow.goToAccountDetails(); + expect( page.url() ).toMatch( 'my-account/edit-account' ); + await expect( page ).toMatchElement( 'h1', { text: 'Account details' } ); + } ); +} ); diff --git a/tests/e2e-tests/specs/front-end/front-end-single-product.test.js b/tests/e2e-tests/specs/front-end/front-end-single-product.test.js new file mode 100644 index 00000000000..0424b11b25c --- /dev/null +++ b/tests/e2e-tests/specs/front-end/front-end-single-product.test.js @@ -0,0 +1,67 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { createSimpleProduct, createVariableProduct } from '../../utils/components'; +import { CustomerFlow, StoreOwnerFlow } from '../../utils/flows'; +import { uiUnblocked } from '../../utils'; + +let simplePostIdValue; +let variablePostIdValue; +const config = require( 'config' ); +const simpleProductName = config.get( 'products.simple.name' ); + +describe( 'Single Product Page', () => { + beforeAll( async () => { + await StoreOwnerFlow.login(); + simplePostIdValue = await createSimpleProduct(); + await StoreOwnerFlow.logout(); + } ); + + it( 'should be able to add simple products to the cart', async () => { + // Add 5 simple products to cart + await CustomerFlow.goToProduct( simplePostIdValue ); + await expect( page ).toFill( 'div.quantity input.qty', '5' ); + await CustomerFlow.addToCart(); + await expect( page ).toMatchElement( '.woocommerce-message', { text: 'have been added to your cart.' } ); + + // Verify cart contents + await CustomerFlow.goToCart(); + await CustomerFlow.productIsInCart( simpleProductName, 5 ); + + // Remove items from cart + await CustomerFlow.removeFromCart( simpleProductName ); + await uiUnblocked(); + await expect( page ).toMatchElement( '.cart-empty', { text: 'Your cart is currently empty.' } ); + } ); +} ); + +describe( 'Variable Product Page', () => { + beforeAll( async () => { + await StoreOwnerFlow.login(); + variablePostIdValue = await createVariableProduct(); + await StoreOwnerFlow.logout(); + } ); + + it( 'should be able to add variation products to the cart', async () => { + // Add a product with one set of variations to cart + await CustomerFlow.goToProduct( variablePostIdValue ); + await expect( page ).toSelect( '#attr-1', 'val1' ); + await expect( page ).toSelect( '#attr-2', 'val1' ); + await expect( page ).toSelect( '#attr-3', 'val1' ); + await CustomerFlow.addToCart(); + await expect( page ).toMatchElement( '.woocommerce-message', { text: 'has been added to your cart.' } ); + + // Verify cart contents + await CustomerFlow.goToCart(); + await CustomerFlow.productIsInCart( 'Variable Product with Three Variations' ); + + // Remove items from cart + await CustomerFlow.removeFromCart( 'Variable Product with Three Variations' ); + await uiUnblocked(); + await expect( page ).toMatchElement( '.cart-empty', { text: 'Your cart is currently empty.' } ); + } ); +} ); diff --git a/tests/e2e-tests/specs/wp-admin/wp-admin-coupon-new.test.js b/tests/e2e-tests/specs/wp-admin/wp-admin-coupon-new.test.js new file mode 100644 index 00000000000..2a51930530a --- /dev/null +++ b/tests/e2e-tests/specs/wp-admin/wp-admin-coupon-new.test.js @@ -0,0 +1,41 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { StoreOwnerFlow } from '../../utils/flows'; +import { clickTab, verifyPublishAndTrash } from '../../utils'; + +describe( 'Add New Coupon Page', () => { + beforeAll( async () => { + await StoreOwnerFlow.login(); + } ); + + it( 'can create new coupon', async () => { + // Go to "add coupon" page + await StoreOwnerFlow.openNewCoupon(); + + // Make sure we're on the add coupon page + await expect( page.title() ).resolves.toMatch( 'Add new coupon' ); + + // Fill in coupon code and description + await expect( page ).toFill( '#title', 'code-' + new Date().getTime().toString() ); + await expect( page ).toFill( '#woocommerce-coupon-description', 'test coupon' ); + + // Set general coupon data + await clickTab( 'General' ); + await expect( page ).toSelect( '#discount_type', 'Fixed cart discount' ); + await expect( page ).toFill( '#coupon_amount', '100' ); + + // Publish coupon, verify that it was published. Trash coupon, verify that it was trashed. + await verifyPublishAndTrash( + '#publish', + '#message', + 'Coupon updated.', + '1 coupon moved to the Trash.' + ); + + } ); +} ); diff --git a/tests/e2e-tests/specs/wp-admin/wp-admin-order-new.test.js b/tests/e2e-tests/specs/wp-admin/wp-admin-order-new.test.js new file mode 100644 index 00000000000..adabaf696a5 --- /dev/null +++ b/tests/e2e-tests/specs/wp-admin/wp-admin-order-new.test.js @@ -0,0 +1,37 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { StoreOwnerFlow } from '../../utils/flows'; +import { verifyPublishAndTrash } from '../../utils'; + +describe( 'Add New Order Page', () => { + beforeAll( async () => { + await StoreOwnerFlow.login(); + } ); + + it( 'can create new order', async () => { + // Go to "add order" page + await StoreOwnerFlow.openNewOrder(); + + // Make sure we're on the add order page + await expect( page.title() ).resolves.toMatch( 'Add new order' ); + + // Set order data + await expect( page ).toSelect( '#order_status', 'Processing' ); + await expect( page ).toFill( 'input[name=order_date]', '2018-12-13' ); + await expect( page ).toFill( 'input[name=order_date_hour]', '18' ); + await expect( page ).toFill( 'input[name=order_date_minute]', '55' ); + + // Create order, verify that it was created. Trash order, verify that it was trashed. + await verifyPublishAndTrash( + '.order_actions li .save_order', + '#message', + 'Order updated.', + '1 order moved to the Trash.' + ); + } ); +} ); diff --git a/tests/e2e-tests/specs/wp-admin/wp-admin-product-new.test.js b/tests/e2e-tests/specs/wp-admin/wp-admin-product-new.test.js new file mode 100644 index 00000000000..e48d2da431d --- /dev/null +++ b/tests/e2e-tests/specs/wp-admin/wp-admin-product-new.test.js @@ -0,0 +1,196 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { StoreOwnerFlow } from '../../utils/flows'; +import { clickTab, uiUnblocked } from '../../utils'; + +const config = require( 'config' ); +const simpleProductName = config.get( 'products.simple.name' ); + +const verifyPublishAndTrash = async () => { + // Wait for auto save + await page.waitFor( 2000 ); + + // Publish product + await expect( page ).toClick( '#publish' ); + await page.waitForSelector( '.updated.notice', { text: 'Product published.' } ); + + // Verify + await expect( page ).toMatchElement( '.updated.notice', { text: 'Product published.' } ); + await page.waitForSelector( 'a', { text: 'Move to Trash' } ); + + // Trash product + await expect( page ).toClick( 'a', { text: 'Move to Trash' } ); + await page.waitForSelector( '.updated.notice', { text: '1 product moved to the Trash.' } ); + + // Verify + await expect( page ).toMatchElement( '.updated.notice', { text: '1 product moved to the Trash.' } ); +}; + +describe( 'Add New Simple Product Page', () => { + beforeAll( async () => { + await StoreOwnerFlow.login(); + } ); + + it( 'can create simple virtual product titled "Simple Product" with regular price $9.99', async () => { + // Go to "add product" page + await StoreOwnerFlow.openNewProduct(); + + // Make sure we're on the add order page + await expect( page.title() ).resolves.toMatch( 'Add new product' ); + + // Set product data + await expect( page ).toFill( '#title', simpleProductName ); + await expect( page ).toClick( '#_virtual' ); + await clickTab( 'General' ); + await expect( page ).toFill( '#_regular_price', '9.99' ); + + // Publish product, verify that it was published. Trash product, verify that it was trashed. + await verifyPublishAndTrash( + '#publish', + '.updated.notice', + 'Product published.', + 'Move to Trash', + '1 product moved to the Trash.' + ); + } ); +} ); + +describe( 'Add New Variable Product Page', () => { + beforeAll( async () => { + await StoreOwnerFlow.login(); + } ); + it( 'can create product with variations', async () => { + // Go to "add product" page + await StoreOwnerFlow.openNewProduct(); + + // Make sure we're on the add order page + await expect( page.title() ).resolves.toMatch( 'Add new product' ); + + // Set product data + await expect( page ).toFill( '#title', 'Variable Product with Three Variations' ); + await expect( page ).toSelect( '#product-type', 'Variable product' ); + + // Create attributes for variations + await clickTab( 'Attributes' ); + await expect( page ).toSelect( 'select[name="attribute_taxonomy"]', 'Custom product attribute' ); + + for ( let i = 0; i < 3; i++ ) { + await expect( page ).toClick( 'button.add_attribute', { text: 'Add' } ); + // Wait for attribute form to load + await uiUnblocked(); + + await page.focus( `input[name="attribute_names[${ i }]"]` ); + await expect( page ).toFill( `input[name="attribute_names[${ i }]"]`, 'attr #' + ( i + 1 ) ); + await expect( page ).toFill( `textarea[name="attribute_values[${ i }]"]`, 'val1 | val2' ); + await expect( page ).toClick( `input[name="attribute_variation[${ i }]"]` ); + } + + await expect( page ).toClick( 'button', { text: 'Save attributes' } ); + + // Wait for attribute form to save (triggers 2 UI blocks) + await uiUnblocked(); + await page.waitFor( 1000 ); + await uiUnblocked(); + + // Create variations from attributes + await clickTab( 'Variations' ); + await page.waitForSelector( 'select.variation_actions:not([disabled])' ); + await page.focus( 'select.variation_actions' ); + await expect( page ).toSelect( 'select.variation_actions', 'Create variations from all attributes' ); + + const firstDialog = await expect( page ).toDisplayDialog( async () => { + // Using this technique since toClick() isn't working. + // See: https://github.com/GoogleChrome/puppeteer/issues/1805#issuecomment-464802876 + page.$eval( 'a.do_variation_action', elem => elem.click() ); + } ); + + expect( firstDialog.message() ).toMatch( 'Are you sure you want to link all variations?' ); + + const secondDialog = await expect( page ).toDisplayDialog( async () => { + await firstDialog.accept(); + } ); + + expect( secondDialog.message() ).toMatch( '8 variations added' ); + await secondDialog.dismiss(); + + // Set some variation data + await uiUnblocked(); + await uiUnblocked(); + + await page.waitForSelector( '.woocommerce_variation .handlediv' ); + + // Verify that variations were created + await Promise.all( [ + expect( page ).toMatchElement( 'select[name="attribute_attr-1[0]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[0]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[0]"]', { text: 'val1' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[1]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[1]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[1]"]', { text: 'val2' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[2]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[2]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[2]"]', { text: 'val1' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[3]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[3]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[3]"]', { text: 'val2' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[4]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[4]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[4]"]', { text: 'val1' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[5]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[5]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[5]"]', { text: 'val2' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[6]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[6]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[6]"]', { text: 'val1' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[7]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[7]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[7]"]', { text: 'val2' } ), + ] ); + + await expect( page ).toClick( '.woocommerce_variation:nth-of-type(2) .handlediv' ); + await page.waitFor( 2000 ); + await page.focus( 'input[name="variable_is_virtual[0]"]' ); + await expect( page ).toClick( 'input[name="variable_is_virtual[0]"]' ); + await expect( page ).toFill( 'input[name="variable_regular_price[0]"]', '9.99' ); + + await expect( page ).toClick( '.woocommerce_variation:nth-of-type(3) .handlediv' ); + await page.waitFor( 2000 ); + await page.focus( 'input[name="variable_is_virtual[1]"]' ); + await expect( page ).toClick( 'input[name="variable_is_virtual[1]"]' ); + await expect( page ).toFill( 'input[name="variable_regular_price[1]"]', '11.99' ); + + await expect( page ).toClick( '.woocommerce_variation:nth-of-type(4) .handlediv' ); + await page.waitFor( 2000 ); + await page.focus( 'input[name="variable_manage_stock[2]"]' ); + await expect( page ).toClick( 'input[name="variable_manage_stock[2]"]' ); + await expect( page ).toFill( 'input[name="variable_regular_price[2]"]', '20' ); + await expect( page ).toFill( 'input[name="variable_weight[2]"]', '200' ); + await expect( page ).toFill( 'input[name="variable_length[2]"]', '10' ); + await expect( page ).toFill( 'input[name="variable_width[2]"]', '20' ); + await expect( page ).toFill( 'input[name="variable_height[2]"]', '15' ); + + await page.focus( 'button.save-variation-changes' ); + await expect( page ).toClick( 'button.save-variation-changes', { text: 'Save changes' } ); + + // Publish product, verify that it was published. Trash product, verify that it was trashed. + await verifyPublishAndTrash( + '#publish', + '.updated.notice', + 'Product published.', + 'Move to Trash', + '1 product moved to the Trash.' + ); + } ); +} ); diff --git a/tests/e2e-tests/specs/wp-admin/wp-admin-settings-general.test.js b/tests/e2e-tests/specs/wp-admin/wp-admin-settings-general.test.js new file mode 100644 index 00000000000..ff229dd4762 --- /dev/null +++ b/tests/e2e-tests/specs/wp-admin/wp-admin-settings-general.test.js @@ -0,0 +1,71 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { StoreOwnerFlow } from '../../utils/flows'; +import { settingsPageSaveChanges, verifyValueOfInputField } from '../../utils'; + +describe( 'WooCommerce General Settings', () => { + beforeAll( async () => { + await StoreOwnerFlow.login(); + } ); + + it( 'can update settings', async () => { + // Go to general settings page + await StoreOwnerFlow.openSettings( 'general' ); + + // Make sure the general tab is active + await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'General' } ); + + // Set selling location to all countries first, + // so we can choose california as base location. + await expect( page ).toSelect( '#woocommerce_allowed_countries', 'Sell to all countries' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + expect( page ).toMatchElement( '#woocommerce_allowed_countries', { text: 'Sell to all countries' } ), + ] ); + + // Set base location with state CA. + await expect( page ).toSelect( 'select[name="woocommerce_default_country"]', 'United States (US) — California' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + expect( page ).toMatchElement( 'select[name="woocommerce_default_country"]', { text: 'United States (US) — California' } ), + ] ); + + // Set selling location to specific countries first, so we can choose U.S as base location (without state). + // This will makes specific countries option appears. + await expect( page ).toSelect( '#woocommerce_allowed_countries', 'Sell to specific countries' ); + await expect( page ).toSelect( 'select[name="woocommerce_specific_allowed_countries[]"]', 'United States (US)' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + expect( page ).toMatchElement( '#woocommerce_allowed_countries', { text: 'Sell to specific countries' } ), + expect( page ).toMatchElement( 'select[name="woocommerce_specific_allowed_countries[]"]', { text: 'United States (US)' } ), + ] ); + + // Set currency options. + await expect( page ).toFill( '#woocommerce_price_thousand_sep', ',' ); + await expect( page ).toFill( '#woocommerce_price_decimal_sep', '.' ); + await expect( page ).toFill( '#woocommerce_price_num_decimals', '2' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + verifyValueOfInputField( '#woocommerce_price_thousand_sep', ',' ), + verifyValueOfInputField( '#woocommerce_price_decimal_sep', '.' ), + verifyValueOfInputField( '#woocommerce_price_num_decimals', '2' ), + ] ); + } ); +} ); diff --git a/tests/e2e-tests/specs/wp-admin/wp-admin-settings-product.test.js b/tests/e2e-tests/specs/wp-admin/wp-admin-settings-product.test.js new file mode 100644 index 00000000000..697df1ed8f2 --- /dev/null +++ b/tests/e2e-tests/specs/wp-admin/wp-admin-settings-product.test.js @@ -0,0 +1,50 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { StoreOwnerFlow } from '../../utils/flows'; +import { setCheckbox, settingsPageSaveChanges, unsetCheckbox, verifyCheckboxIsSet, verifyCheckboxIsUnset } from '../../utils'; + +describe( 'WooCommerce Products > Downloadable Products Settings', () => { + beforeAll( async () => { + await StoreOwnerFlow.login(); + } ); + + it( 'can update settings', async () => { + // Go to downloadable products settings page + await StoreOwnerFlow.openSettings( 'products', 'downloadable' ); + + // Make sure the product tab is active + await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'Products' } ); + await expect( page ).toMatchElement( 'ul.subsubsub > li > a.current', { text: 'Downloadable products' } ); + + await expect( page ).toSelect( '#woocommerce_file_download_method', 'Redirect only' ); + await setCheckbox( '#woocommerce_downloads_require_login' ); + await setCheckbox( '#woocommerce_downloads_grant_access_after_payment' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + expect( page ).toMatchElement( '#woocommerce_file_download_method', { text: 'Redirect only' } ), + verifyCheckboxIsSet( '#woocommerce_downloads_require_login' ), + verifyCheckboxIsSet( '#woocommerce_downloads_grant_access_after_payment' ), + ] ); + + await expect( page ).toSelect( '#woocommerce_file_download_method', 'Force downloads' ); + await unsetCheckbox( '#woocommerce_downloads_require_login' ); + await unsetCheckbox( '#woocommerce_downloads_grant_access_after_payment' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + expect( page ).toMatchElement( '#woocommerce_file_download_method', { text: 'Force downloads' } ), + verifyCheckboxIsUnset( '#woocommerce_downloads_require_login' ), + verifyCheckboxIsUnset( '#woocommerce_downloads_grant_access_after_payment' ), + ] ); + } ); +} ); diff --git a/tests/e2e-tests/specs/wp-admin/wp-admin-settings-tax.test.js b/tests/e2e-tests/specs/wp-admin/wp-admin-settings-tax.test.js new file mode 100644 index 00000000000..3d3ca888e26 --- /dev/null +++ b/tests/e2e-tests/specs/wp-admin/wp-admin-settings-tax.test.js @@ -0,0 +1,170 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { StoreOwnerFlow } from '../../utils/flows'; +import { + clearAndFillInput, + setCheckbox, + settingsPageSaveChanges, + uiUnblocked, + verifyCheckboxIsSet, + verifyValueOfInputField +} from '../../utils'; + +describe( 'WooCommerce Tax Settings', () => { + beforeAll( async () => { + await StoreOwnerFlow.login(); + } ); + + it( 'can enable tax calculation', async() => { + // Go to general settings page + await StoreOwnerFlow.openSettings( 'general' ); + + // Make sure the general tab is active + await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'General' } ); + + // Enable tax calculation + await setCheckbox( 'input[name="woocommerce_calc_taxes"]' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + verifyCheckboxIsSet( '#woocommerce_calc_taxes' ), + ] ); + + // Verify that tax settings are now present + await expect( page ).toMatchElement( 'a.nav-tab', { text: 'Tax' } ); + } ); + + it( 'can set tax options', async () => { + // Go to tax settings page + await StoreOwnerFlow.openSettings( 'tax' ); + + // Make sure the tax tab is active + await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'Tax' } ); + + // Prices exclusive of tax + await expect( page ).toClick( 'input[name="woocommerce_prices_include_tax"][value="no"]' ); + // Tax based on customer shipping address + await expect( page ).toSelect( '#woocommerce_tax_based_on', 'Customer shipping address' ); + // Standard tax class for shipping + await expect( page ).toSelect( '#woocommerce_shipping_tax_class', 'Standard' ); + // Leave rounding unchecked (no-op) + // Display prices excluding tax + await expect( page ).toSelect( '#woocommerce_tax_display_shop', 'Excluding tax' ); + // Display prices including tax in cart and at checkout + await expect( page ).toSelect( '#woocommerce_tax_display_cart', 'Including tax' ); + // Display a single tax total + await expect( page ).toSelect( '#woocommerce_tax_total_display', 'As a single total' ); + + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + verifyValueOfInputField( 'input[name="woocommerce_prices_include_tax"][value="no"]', 'no' ), + expect( page ).toMatchElement( '#woocommerce_tax_based_on', { text: 'Customer shipping address' } ), + expect( page ).toMatchElement( '#woocommerce_shipping_tax_class', { text: 'Standard' } ), + expect( page ).toMatchElement( '#woocommerce_tax_display_shop', { text: 'Excluding tax' } ), + expect( page ).toMatchElement( '#woocommerce_tax_display_cart', { text: 'Including tax' } ), + expect( page ).toMatchElement( '#woocommerce_tax_total_display', { text: 'As a single total' } ), + ] ); + } ); + + it( 'can add tax classes', async () => { + // Go to tax settings page + await StoreOwnerFlow.openSettings( 'tax' ); + + // Make sure the tax tab is active + await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'Tax' } ); + + // Remove additional tax classes + await clearAndFillInput( '#woocommerce_tax_classes', '' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + expect( page ).toMatchElement( '#woocommerce_tax_classes', { text: '' } ), + ] ); + + // Add a "fancy" tax class + await clearAndFillInput( '#woocommerce_tax_classes', 'Fancy' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + expect( page ).toMatchElement( 'ul.subsubsub > li > a', { text: 'Fancy rates' } ), + ] ); + } ); + + it( 'can set rate settings', async () => { + // Go to "fancy" rates tax settings page + await StoreOwnerFlow.openSettings( 'tax', 'fancy' ); + + // Make sure the tax tab is active, with the "fancy" subsection + await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'Tax' } ); + await expect( page ).toMatchElement( 'ul.subsubsub > li > a.current', { text: 'Fancy rates' } ); + + // Create a state tax + await expect( page ).toClick( '.wc_tax_rates a.insert' ); + await expect( page ).toFill( 'input[name^="tax_rate_country[new-0"]', 'US' ); + await expect( page ).toFill( 'input[name^="tax_rate_state[new-0"]', 'CA' ); + await expect( page ).toFill( 'input[name^="tax_rate[new-0"]', '7.5' ); + await expect( page ).toFill( 'input[name^="tax_rate_name[new-0"]', 'CA State Tax' ); + + // Create a federal tax + await expect( page ).toClick( '.wc_tax_rates a.insert' ); + await expect( page ).toFill( 'input[name^="tax_rate_country[new-1"]', 'US' ); + await expect( page ).toFill( 'input[name^="tax_rate[new-1"]', '1.5' ); + await expect( page ).toFill( 'input[name^="tax_rate_priority[new-1"]', '2' ); + await expect( page ).toFill( 'input[name^="tax_rate_name[new-1"]', 'Federal Tax' ); + await expect( page ).toClick( 'input[name^="tax_rate_shipping[new-1"]' ); + + // Save changes (AJAX here) + await expect( page ).toClick( 'button.woocommerce-save-button' ); + await uiUnblocked(); + + // Verify 2 tax rates + expect( await page.$$( '#rates tr' ) ).toHaveLength( 2 ); + + // Delete federal rate + await expect( page ).toClick( '#rates tr:nth-child(2) input' ); + await expect( page ).toClick( '.wc_tax_rates a.remove_tax_rates' ); + + // Save changes (AJAX here) + await expect( page ).toClick( 'button.woocommerce-save-button' ); + await uiUnblocked(); + + // Verify 1 rate + expect( await page.$$( '#rates tr' ) ).toHaveLength( 1 ); + await expect( page ).toMatchElement( + '#rates tr:first-of-type input[name^="tax_rate_state"][value="CA"]' + ); + } ); + + it( 'can remove tax classes', async () => { + // Go to tax settings page + await StoreOwnerFlow.openSettings( 'tax' ); + + // Make sure the tax tab is active + await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'Tax' } ); + + // Remove "fancy" tax class + await clearAndFillInput( '#woocommerce_tax_classes', ' ' ); + await settingsPageSaveChanges(); + + // Verify that settings have been saved + await Promise.all( [ + expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ), + expect( page ).not.toMatchElement( 'ul.subsubsub > li > a', { text: 'Fancy rates' } ), + ] ); + await page.waitFor( 10000 ); + } ); +} ); diff --git a/tests/e2e-tests/utils/components.js b/tests/e2e-tests/utils/components.js new file mode 100644 index 00000000000..9c96d19da03 --- /dev/null +++ b/tests/e2e-tests/utils/components.js @@ -0,0 +1,322 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { StoreOwnerFlow } from './flows'; +import { clickTab, uiUnblocked, verifyCheckboxIsUnset } from './index'; + +const config = require( 'config' ); +const simpleProductName = config.get( 'products.simple.name' ); + +const verifyAndPublish = async () => { + // Wait for auto save + await page.waitFor( 2000 ); + + // Publish product + await expect( page ).toClick( '#publish' ); + await page.waitForSelector( '.updated.notice' ); + + // Verify + await expect( page ).toMatchElement( '.updated.notice', { text: 'Product published.' } ); +}; + +/** + * Complete old setup wizard. + */ +const completeOldSetupWizard = async () => { + // Fill out store setup section details + // Select country where the store is located + await expect( page ).toSelect( 'select[name="store_country"]', config.get( 'addresses.admin.store.country' ) ); + // Fill store's address - first line + await expect( page ).toFill( '#store_address', config.get( 'addresses.admin.store.addressfirstline' ) ); + + // Fill store's address - second line + await expect( page ).toFill( '#store_address_2', config.get( 'addresses.admin.store.addresssecondline' ) ); + + // Fill the city where the store is located + await expect( page ).toFill( '#store_city', config.get( 'addresses.admin.store.city' ) ); + + // Select the state where the store is located + await expect( page ).toSelect( 'select[name="store_state"]', config.get( 'addresses.admin.store.state') ); + + // Fill postcode of the store + await expect( page ).toFill( '#store_postcode', config.get( 'addresses.admin.store.postcode' ) ); + + // Select currency and type of products to sell details + await expect( page ).toSelect( 'select[name="currency_code"]', '\n' + + '\t\t\t\t\t\tUnited States (US) dollar ($ USD)\t\t\t\t\t' ); + await expect( page ).toSelect( 'select[name="product_type"]', 'I plan to sell both physical and digital products' ); + + // Verify that checkbox next to "I will also be selling products or services in person." is not selected + await verifyCheckboxIsUnset( '#woocommerce_sell_in_person' ); + + // Click on "Let's go!" button to move to the next step + await page.$eval( 'button[name=save_step]', elem => elem.click() ); + + // Wait for usage tracking pop-up window to appear + await page.waitForSelector( '#wc-backbone-modal-dialog' ); + await expect( page ).toMatchElement( + '.wc-backbone-modal-header', { text: 'Help improve WooCommerce with usage tracking' } + ); + + await page.waitForSelector( '#wc_tracker_checkbox_dialog' ); + + // Verify that checkbox next to "Enable usage tracking and help improve WooCommerce" is not selected + await verifyCheckboxIsUnset( '#wc_tracker_checkbox_dialog' ); + + await Promise.all( [ + // Click on "Continue" button to move to the next step + page.$eval( '#wc_tracker_submit', elem => elem.click() ), + + // Wait for the Payment section to load + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ] ); + + // Fill out payment section details + // Turn off Stripe account toggle + await page.click( '.wc-wizard-service-toggle' ); + + await Promise.all( [ + // Click on "Continue" button to move to the next step + page.click( 'button[name=save_step]', { text: 'Continue' } ), + + // Wait for the Shipping section to load + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ] ); + + // Fill out shipping section details + // Turn off WooCommerce Shipping option + await page.$eval( '#wc_recommended_woocommerce_services', elem => elem.click() ); + + await page.waitForSelector( 'select[name="shipping_zones[domestic][method]"]' ); + await page.waitForSelector( 'select[name="shipping_zones[intl][method]"]' ); + + // Select Flat Rate shipping method for domestic shipping zone + await page.evaluate( () => { + document.querySelector( 'select[name="shipping_zones[domestic][method]"] > option:nth-child(1)' ).selected = true; + let element = document.querySelector( 'select[name="shipping_zones[domestic][method]"]' ); + let event = new Event( 'change', { bubbles: true } ); + event.simulated = true; + element.dispatchEvent( event ); + } ); + + await page.$eval( 'input[name="shipping_zones[domestic][flat_rate][cost]"]', e => e.setAttribute( 'value', '10.00' ) ); + + // Select Flat Rate shipping method for the rest of the world shipping zone + await page.evaluate( () => { + document.querySelector( 'select[name="shipping_zones[intl][method]"] > option:nth-child(1)' ).selected = true; + let element = document.querySelector( 'select[name="shipping_zones[intl][method]"]' ); + let event = new Event( 'change', { bubbles: true } ); + event.simulated = true; + element.dispatchEvent( event ); + } ); + + await page.$eval( 'input[name="shipping_zones[intl][flat_rate][cost]"]', e => e.setAttribute( 'value', '20.00' ) ); + + // Select product weight and product dimensions options + await expect( page ).toSelect( 'select[name="weight_unit"]', 'Pounds' ); + await expect( page ).toSelect( 'select[name="dimension_unit"]', 'Inches' ); + + await Promise.all( [ + // Click on "Continue" button to move to the next step + page.click( 'button[name=save_step]', { text: 'Continue' } ), + + // Wait for the Recommended section to load + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ] ); + + // Fill out recommended section details + // Turn off Storefront Theme option + // await page.waitForSelector( '#wc_recommended_storefront_theme', { visible: true } ); + // await page.$eval( '#wc_recommended_storefront_theme', elem => elem.click() ); + + // Turn off Automated Taxes option + await page.waitForSelector( '#wc_recommended_automated_taxes', { visible: true } ); + await page.$eval( '#wc_recommended_automated_taxes', elem => elem.click() ); + + // Turn off WooCommerce Admin option + await page.waitForSelector( '#wc_recommended_wc_admin', { visible: true } ); + await page.$eval( '#wc_recommended_wc_admin', elem => elem.click() ); + + // Turn off Mailchimp option + await page.waitForSelector( '#wc_recommended_mailchimp', { visible: true } ); + await page.$eval( '#wc_recommended_mailchimp', elem => elem.click() ); + + // Turn off Facebook option + await page.waitForSelector( '#wc_recommended_facebook', { visible: true } ); + await page.$eval( '#wc_recommended_facebook', elem => elem.click() ); + + await Promise.all( [ + // Click on "Continue" button to move to the next step + page.click( 'button[name=save_step]', { text: 'Continue' } ), + + // Wait for the Jetpack section to load + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ] ); + + // Skip activate Jetpack section + // Click on "Skip this step" in order to skip Jetpack installation + await page.click( '.wc-setup-footer-links' ); + + // Finish Setup Wizard - Ready! section + // Visit Dashboard + await StoreOwnerFlow.openDashboard(); +} ; + +/** + * Create simple product. + */ +const createSimpleProduct = async () => { + // Go to "add product" page + await StoreOwnerFlow.openNewProduct(); + + // Make sure we're on the add order page + await expect( page.title() ).resolves.toMatch( 'Add new product' ); + + // Set product data + await expect( page ).toFill( '#title', simpleProductName ); + await clickTab( 'General' ); + await expect( page ).toFill( '#_regular_price', '9.99' ); + + await verifyAndPublish(); + + const simplePostId = await page.$( '#post_ID' ); + let simplePostIdValue = ( await ( await simplePostId.getProperty( 'value' ) ).jsonValue() ); + return simplePostIdValue; +} ; + +/** + * Create variable product. + */ +const createVariableProduct = async () => { + // Go to "add product" page + await StoreOwnerFlow.openNewProduct(); + + // Make sure we're on the add order page + await expect( page.title() ).resolves.toMatch( 'Add new product' ); + + // Set product data + await expect( page ).toFill( '#title', 'Variable Product with Three Variations' ); + await expect( page ).toSelect( '#product-type', 'Variable product' ); + + // Create attributes for variations + await clickTab( 'Attributes' ); + await expect( page ).toSelect( 'select[name="attribute_taxonomy"]', 'Custom product attribute' ); + + for ( let i = 0; i < 3; i++ ) { + await expect( page ).toClick( 'button.add_attribute', { text: 'Add' } ); + // Wait for attribute form to load + await uiUnblocked(); + + await page.focus( `input[name="attribute_names[${ i }]"]` ); + await expect( page ).toFill( `input[name="attribute_names[${ i }]"]`, 'attr #' + ( i + 1 ) ); + await expect( page ).toFill( `textarea[name="attribute_values[${ i }]"]`, 'val1 | val2' ); + await expect( page ).toClick( `input[name="attribute_variation[${ i }]"]` ); + } + + await expect( page ).toClick( 'button', { text: 'Save attributes' } ); + + // Wait for attribute form to save (triggers 2 UI blocks) + await uiUnblocked(); + await page.waitFor( 1000 ); + await uiUnblocked(); + + // Create variations from attributes + await clickTab( 'Variations' ); + await page.waitForSelector( 'select.variation_actions:not([disabled])' ); + await page.focus( 'select.variation_actions' ); + await expect( page ).toSelect( 'select.variation_actions', 'Create variations from all attributes' ); + + const firstDialog = await expect( page ).toDisplayDialog( async () => { + // Using this technique since toClick() isn't working. + // See: https://github.com/GoogleChrome/puppeteer/issues/1805#issuecomment-464802876 + page.$eval( 'a.do_variation_action', elem => elem.click() ); + + } ); + + expect( firstDialog.message() ).toMatch( 'Are you sure you want to link all variations?' ); + + const secondDialog = await expect( page ).toDisplayDialog( async () => { + await firstDialog.accept(); + } ); + + expect( secondDialog.message() ).toMatch( '8 variations added' ); + await secondDialog.dismiss(); + + // Set some variation data + await uiUnblocked(); + await uiUnblocked(); + + await page.waitForSelector( '.woocommerce_variation .handlediv' ); + + // Verify that variations were created + await Promise.all( [ + expect( page ).toMatchElement( 'select[name="attribute_attr-1[0]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[0]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[0]"]', { text: 'val1' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[1]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[1]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[1]"]', { text: 'val2' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[2]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[2]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[2]"]', { text: 'val1' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[3]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[3]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[3]"]', { text: 'val2' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[4]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[4]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[4]"]', { text: 'val1' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[5]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[5]"]', { text: 'val1' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[5]"]', { text: 'val2' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[6]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[6]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[6]"]', { text: 'val1' } ), + + expect( page ).toMatchElement( 'select[name="attribute_attr-1[7]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-2[7]"]', { text: 'val2' } ), + expect( page ).toMatchElement( 'select[name="attribute_attr-3[7]"]', { text: 'val2' } ), + ] ); + + await expect( page ).toClick( '.woocommerce_variation:nth-of-type(2) .handlediv' ); + await page.waitFor( 2000 ); + await page.focus( 'input[name="variable_is_virtual[0]"]' ); + await expect( page ).toClick( 'input[name="variable_is_virtual[0]"]' ); + await expect( page ).toFill( 'input[name="variable_regular_price[0]"]', '9.99' ); + + await expect( page ).toClick( '.woocommerce_variation:nth-of-type(3) .handlediv' ); + await page.waitFor( 2000 ); + await page.focus( 'input[name="variable_is_virtual[1]"]' ); + await expect( page ).toClick( 'input[name="variable_is_virtual[1]"]' ); + await expect( page ).toFill( 'input[name="variable_regular_price[1]"]', '11.99' ); + + await expect( page ).toClick( '.woocommerce_variation:nth-of-type(4) .handlediv' ); + await page.waitFor( 2000 ); + await page.focus( 'input[name="variable_manage_stock[2]"]' ); + await expect( page ).toClick( 'input[name="variable_manage_stock[2]"]' ); + await expect( page ).toFill( 'input[name="variable_regular_price[2]"]', '20' ); + await expect( page ).toFill( 'input[name="variable_weight[2]"]', '200' ); + await expect( page ).toFill( 'input[name="variable_length[2]"]', '10' ); + await expect( page ).toFill( 'input[name="variable_width[2]"]', '20' ); + await expect( page ).toFill( 'input[name="variable_height[2]"]', '15' ); + + await page.focus( 'button.save-variation-changes' ); + await expect( page ).toClick( 'button.save-variation-changes', { text: 'Save changes' } ); + + await verifyAndPublish(); + + const variablePostId = await page.$( '#post_ID' ); + let variablePostIdValue = ( await ( await variablePostId.getProperty( 'value' ) ).jsonValue() ); + return variablePostIdValue; +}; + +export { completeOldSetupWizard, createSimpleProduct, createVariableProduct }; diff --git a/tests/e2e-tests/utils/flows.js b/tests/e2e-tests/utils/flows.js new file mode 100644 index 00000000000..50ea2716937 --- /dev/null +++ b/tests/e2e-tests/utils/flows.js @@ -0,0 +1,317 @@ +/** + * @format + */ + +/** + * External dependencies + */ +import { pressKeyWithModifier } from '@wordpress/e2e-test-utils'; + +/** + * Internal dependencies + */ +import { clearAndFillInput } from './index'; + +const config = require( 'config' ); +const baseUrl = config.get( 'url' ); + +const WP_ADMIN_LOGIN = baseUrl + 'wp-login.php'; +const WP_ADMIN_DASHBOARD = baseUrl + 'wp-admin'; +const WP_ADMIN_PLUGINS = baseUrl + 'wp-admin/plugins.php'; +const WP_ADMIN_SETUP_WIZARD = baseUrl + 'wp-admin/admin.php?page=wc-setup'; +const WP_ADMIN_ALL_ORDERS_VIEW = baseUrl + 'wp-admin/edit.php?post_type=shop_order'; +const WP_ADMIN_NEW_COUPON = baseUrl + 'wp-admin/post-new.php?post_type=shop_coupon'; +const WP_ADMIN_NEW_ORDER = baseUrl + 'wp-admin/post-new.php?post_type=shop_order'; +const WP_ADMIN_NEW_PRODUCT = baseUrl + 'wp-admin/post-new.php?post_type=product'; +const WP_ADMIN_WC_SETTINGS = baseUrl + 'wp-admin/admin.php?page=wc-settings&tab='; +const WP_ADMIN_PERMALINK_SETTINGS = baseUrl + 'wp-admin/options-permalink.php'; + +const SHOP_PAGE = baseUrl + 'shop'; +const SHOP_PRODUCT_PAGE = baseUrl + '?p='; +const SHOP_CART_PAGE = baseUrl + 'cart'; +const SHOP_CHECKOUT_PAGE = baseUrl + 'checkout/'; +const SHOP_MY_ACCOUNT_PAGE = baseUrl + 'my-account/'; + +const MY_ACCOUNT_ORDERS = baseUrl + 'my-account/orders'; +const MY_ACCOUNT_DOWNLOADS = baseUrl + 'my-account/downloads'; +const MY_ACCOUNT_ADDRESSES = baseUrl + 'my-account/edit-address'; +const MY_ACCOUNT_ACCOUNT_DETAILS = baseUrl + 'my-account/edit-account'; + +const getProductColumnExpression = ( productTitle ) => ( + 'td[@class="product-name" and ' + + `a[contains(text(), "${ productTitle }")]` + + ']' +); + +const getQtyColumnExpression = ( args ) => ( + 'td[@class="product-quantity" and ' + + './/' + getQtyInputExpression( args ) + + ']' +); + +const getQtyInputExpression = ( args = {} ) => { + let qtyValue = ''; + + if ( args.checkQty ) { + qtyValue = ` and @value="${ args.qty }"`; + } + + return 'input[contains(@class, "input-text")' + qtyValue + ']'; +}; + +const getCartItemExpression = ( productTitle, args ) => ( + '//tr[contains(@class, "cart_item") and ' + + getProductColumnExpression( productTitle ) + + ' and ' + + getQtyColumnExpression( args ) + + ']' +); + +const getRemoveExpression = () => ( + 'td[@class="product-remove"]//a[@class="remove"]' +); + +const CustomerFlow = { + addToCart: async () => { + await Promise.all( [ + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + page.click( '.single_add_to_cart_button' ), + ] ); + }, + + addToCartFromShopPage: async ( productTitle ) => { + const addToCartXPath = `//li[contains(@class, "type-product") and a/h2[contains(text(), "${ productTitle }")]]` + + '//a[contains(@class, "add_to_cart_button") and contains(@class, "ajax_add_to_cart")'; + + const [ addToCartButton ] = await page.$x( addToCartXPath + ']' ); + addToCartButton.click(); + + await page.waitFor( addToCartXPath + ' and contains(@class, "added")]' ); + }, + + goToCheckout: async () => { + await page.goto( SHOP_CHECKOUT_PAGE, { + waitUntil: 'networkidle0', + } ); + }, + + goToOrders: async () => { + await page.goto( MY_ACCOUNT_ORDERS, { + waitUntil: 'networkidle0', + } ); + }, + + goToDownloads: async () => { + await page.goto( MY_ACCOUNT_DOWNLOADS, { + waitUntil: 'networkidle0', + } ); + }, + + goToAddresses: async () => { + await page.goto( MY_ACCOUNT_ADDRESSES, { + waitUntil: 'networkidle0', + } ); + }, + + goToAccountDetails: async () => { + await page.goto( MY_ACCOUNT_ACCOUNT_DETAILS, { + waitUntil: 'networkidle0', + } ); + }, + + goToProduct: async ( postID ) => { + await page.goto( SHOP_PRODUCT_PAGE + postID, { + waitUntil: 'networkidle0', + } ); + }, + + + goToShop: async () => { + await page.goto(SHOP_PAGE, { + waitUntil: 'networkidle0', + }); + }, + + placeOrder: async () => { + await Promise.all( [ + expect( page ).toClick( '#place_order' ), + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ] ); + }, + + productIsInCheckout: async ( productTitle, quantity, total, cartSubtotal ) => { + await expect( page ).toMatchElement( '.product-name', { text: productTitle } ); + await expect( page ).toMatchElement( '.product-quantity', { text: quantity } ); + await expect( page ).toMatchElement( '.product-total .amount', { text: total } ); + await expect( page ).toMatchElement( '.cart-subtotal .amount', { text: cartSubtotal } ); + }, + + goToCart: async () => { + await page.goto( SHOP_CART_PAGE, { + waitUntil: 'networkidle0', + } ); + }, + + login: async () => { + await page.goto( SHOP_MY_ACCOUNT_PAGE, { + waitUntil: 'networkidle0', + } ); + + await expect( page.title() ).resolves.toMatch( 'My account' ); + + await page.type( '#username', config.get('users.customer.username') ); + await page.type( '#password', config.get('users.customer.password') ); + + await Promise.all( [ + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + page.click( 'button[name="login"]' ), + ] ); + }, + + productIsInCart: async ( productTitle, quantity = null ) => { + const cartItemArgs = quantity ? { qty: quantity } : {}; + const cartItemXPath = getCartItemExpression( productTitle, cartItemArgs ); + + await expect( page.$x( cartItemXPath ) ).resolves.toHaveLength( 1 ); + }, + + fillBillingDetails: async ( customerBillingDetails ) => { + await expect( page ).toFill( '#billing_first_name', customerBillingDetails.firstname ); + await expect( page ).toFill( '#billing_last_name', customerBillingDetails.lastname ); + await expect( page ).toFill( '#billing_company', customerBillingDetails.company ); + await expect( page ).toSelect( '#billing_country', customerBillingDetails.country ); + await expect( page ).toFill( '#billing_address_1', customerBillingDetails.addressfirstline ); + await expect( page ).toFill( '#billing_address_2', customerBillingDetails.addresssecondline ); + await expect( page ).toFill( '#billing_city', customerBillingDetails.city ); + await expect( page ).toSelect( '#billing_state', customerBillingDetails.state ); + await expect( page ).toFill( '#billing_postcode', customerBillingDetails.postcode ); + await expect( page ).toFill( '#billing_phone', customerBillingDetails.phone ); + await expect( page ).toFill( '#billing_email', customerBillingDetails.email ); + }, + + fillShippingDetails: async ( customerShippingDetails ) => { + await expect( page ).toFill( '#shipping_first_name', customerShippingDetails.firstname ); + await expect( page ).toFill( '#shipping_last_name', customerShippingDetails.lastname ); + await expect( page ).toFill( '#shipping_company', customerShippingDetails.company ); + await expect( page ).toSelect( '#shipping_country', customerShippingDetails.country ); + await expect( page ).toFill( '#shipping_address_1', customerShippingDetails.addressfirstline ); + await expect( page ).toFill( '#shipping_address_2', customerShippingDetails.addresssecondline ); + await expect( page ).toFill( '#shipping_city', customerShippingDetails.city ); + await expect( page ).toSelect( '#shipping_state', customerShippingDetails.state ); + await expect( page ).toFill( '#shipping_postcode', customerShippingDetails.postcode ); + }, + + removeFromCart: async ( productTitle ) => { + const cartItemXPath = getCartItemExpression(productTitle); + const removeItemXPath = cartItemXPath + '//' + getRemoveExpression(); + + const [removeButton] = await page.$x(removeItemXPath); + await removeButton.click(); + }, + + setCartQuantity: async ( productTitle, quantityValue ) => { + const cartItemXPath = getCartItemExpression( productTitle ); + const quantityInputXPath = cartItemXPath + '//' + getQtyInputExpression(); + + const [ quantityInput ] = await page.$x( quantityInputXPath ); + await quantityInput.focus(); + await pressKeyWithModifier( 'primary', 'a' ); + await quantityInput.type( quantityValue.toString() ); + }, +}; + + +const StoreOwnerFlow = { + login: async () => { + await page.goto( WP_ADMIN_LOGIN, { + waitUntil: 'networkidle0', + } ); + + await expect( page.title() ).resolves.toMatch( 'Log In' ); + + await clearAndFillInput( '#user_login', ' ' ); + + await page.type( '#user_login', config.get( 'users.admin.username' ) ); + await page.type( '#user_pass', config.get( 'users.admin.password' ) ); + + await Promise.all( [ + page.click( 'input[type=submit]' ), + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ] ); + }, + + logout: async () => { + await page.goto(baseUrl + 'wp-login.php?action=logout', { + waitUntil: 'networkidle0', + }); + + await expect(page).toMatch('You are attempting to log out'); + + await Promise.all([ + page.waitForNavigation({ waitUntil: 'networkidle0' }), + page.click('a'), + ]); + }, + + openAllOrdersView: async () => { + await page.goto( WP_ADMIN_ALL_ORDERS_VIEW, { + waitUntil: 'networkidle0', + } ); + }, + + openDashboard: async () => { + await page.goto( WP_ADMIN_DASHBOARD, { + waitUntil: 'networkidle0', + } ); + }, + + openNewCoupon: async () => { + await page.goto( WP_ADMIN_NEW_COUPON, { + waitUntil: 'networkidle0', + } ); + }, + + openNewOrder: async () => { + await page.goto( WP_ADMIN_NEW_ORDER, { + waitUntil: 'networkidle0', + } ); + }, + + openNewProduct: async () => { + await page.goto( WP_ADMIN_NEW_PRODUCT, { + waitUntil: 'networkidle0', + } ); + }, + + openPermalinkSettings: async () => { + await page.goto( WP_ADMIN_PERMALINK_SETTINGS, { + waitUntil: 'networkidle0', + } ); + }, + + openPlugins: async () => { + await page.goto( WP_ADMIN_PLUGINS, { + waitUntil: 'networkidle0', + } ); + }, + + openSettings: async ( tab, section = null ) => { + let settingsUrl = WP_ADMIN_WC_SETTINGS + tab; + + if ( section ) { + settingsUrl += `§ion=${ section }`; + } + + await page.goto( settingsUrl, { + waitUntil: 'networkidle0', + } ); + }, + + runSetupWizard: async () => { + await page.goto( WP_ADMIN_SETUP_WIZARD, { + waitUntil: 'networkidle0', + } ); + }, +}; + +export { CustomerFlow, StoreOwnerFlow }; diff --git a/tests/e2e-tests/utils/index.js b/tests/e2e-tests/utils/index.js new file mode 100644 index 00000000000..905c19d6156 --- /dev/null +++ b/tests/e2e-tests/utils/index.js @@ -0,0 +1,175 @@ +/** + * External dependencies + */ +import { pressKeyWithModifier } from '@wordpress/e2e-test-utils'; + +/** + * Internal dependencies + */ +const flows = require( './flows' ); + +/** + * Perform a "select all" and then fill a input. + * + * @param {string} selector + * @param {string} value + */ +const clearAndFillInput = async ( selector, value ) => { + await page.focus( selector ); + await pressKeyWithModifier( 'primary', 'a' ); + await page.type( selector, value ); +}; + +/** + * Click a tab (on post type edit screen). + * + * @param {string} tabName Tab label + */ +const clickTab = async ( tabName ) => { + await expect( page ).toClick( '.wc-tabs > li > a', { text: tabName } ); +}; + +/** + * Save changes on a WooCommerce settings page. + */ +const settingsPageSaveChanges = async () => { + await page.focus( 'button.woocommerce-save-button' ); + await Promise.all( [ + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + page.click( 'button.woocommerce-save-button' ), + ] ); +}; + +/** + * Save changes on Permalink settings page. + */ +const permalinkSettingsPageSaveChanges = async () => { + await page.focus( '.wp-core-ui .button-primary' ); + await Promise.all( [ + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + page.click( '.wp-core-ui .button-primary' ), + ] ); +}; + +/** + * Set checkbox. + * + * @param {string} selector + */ +const setCheckbox = async( selector ) => { + await page.focus( selector ); + const checkbox = await page.$( selector ); + const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); + if ( checkboxStatus !== true ) { + await page.click( selector ); + } +}; + +/** + * Unset checkbox. + * + * @param {string} selector + */ +const unsetCheckbox = async( selector ) => { + await page.focus( selector ); + const checkbox = await page.$( selector ); + const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); + if ( checkboxStatus === true ) { + await page.click( selector ); + } +}; + +/** + * Wait for UI blocking to end. + */ +const uiUnblocked = async () => { + await page.waitForFunction( () => ! Boolean( document.querySelector( '.blockUI' ) ) ); +}; + +/** + * Publish, verify that item was published. Trash, verify that item was trashed. + * + * @param {string} button (Publish) + * @param {string} publishNotice + * @param {string} publishVerification + * @param {string} trashVerification + */ +const verifyPublishAndTrash = async ( button, publishNotice, publishVerification, trashVerification ) => { + // Wait for auto save + await page.waitFor( 2000 ); + + // Publish + await expect( page ).toClick( button ); + await page.waitForSelector( publishNotice ); + + // Verify + await expect( page ).toMatchElement( publishNotice, { text: publishVerification } ); + if ( button === '.order_actions li .save_order' ) { + await expect( page ).toMatchElement( '#select2-order_status-container', { text: 'Processing' } ); + await expect( page ).toMatchElement( + '#woocommerce-order-notes .note_content', + { + text: 'Order status changed from Pending payment to Processing.', + } + ); + } + + // Trash + await expect( page ).toClick( 'a', { text: "Move to Trash" } ); + await page.waitForSelector( '#message' ); + + // Verify + await expect( page ).toMatchElement( publishNotice, { text: trashVerification } ); +}; + +/** + * Verify that checkbox is set. + * + * @param {string} selector Selector of the checkbox that needs to be verified. + */ +const verifyCheckboxIsSet = async( selector ) => { + await page.focus( selector ); + const checkbox = await page.$( selector ); + const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); + await expect( checkboxStatus ).toBe( true ); +}; + +/** + * Verify that checkbox is unset. + * + * @param {string} selector Selector of the checkbox that needs to be verified. + */ +const verifyCheckboxIsUnset = async( selector ) => { + await page.focus( selector ); + const checkbox = await page.$( selector ); + const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); + await expect( checkboxStatus ).not.toBe( true ); +}; + +/** + * Verify the value of input field once it was saved (can be used for radio buttons verification as well). + * + * @param {string} selector Selector of the input field that needs to be verified. + * @param {string} value Value of the input field that needs to be verified. + */ +const verifyValueOfInputField = async( selector, value ) => { + await page.focus( selector ); + const field = await page.$( selector ); + const fieldValue = ( await ( await field.getProperty( 'value' ) ).jsonValue() ); + await expect( fieldValue ).toBe( value ); +}; + +module.exports = { + ...flows, + clearAndFillInput, + clickTab, + settingsPageSaveChanges, + permalinkSettingsPageSaveChanges, + setCheckbox, + unsetCheckbox, + uiUnblocked, + verifyPublishAndTrash, + verifyCheckboxIsSet, + verifyCheckboxIsUnset, + verifyValueOfInputField, +}; diff --git a/tests/e2e-tests/wp-admin/wp-admin-coupon-new.js b/tests/e2e-tests/wp-admin/wp-admin-coupon-new.js deleted file mode 100644 index a459abfbe26..00000000000 --- a/tests/e2e-tests/wp-admin/wp-admin-coupon-new.js +++ /dev/null @@ -1,60 +0,0 @@ -import config from 'config'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import test from 'selenium-webdriver/testing'; -import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; -import { StoreOwnerFlow } from 'wc-e2e-page-objects'; - -chai.use( chaiAsPromised ); -const assert = chai.assert; - -let manager; -let driver; - -test.describe( 'Add New Coupon Page', function() { - // open browser - test.before( function() { - this.timeout( config.get( 'startBrowserTimeoutMs' ) ); - - manager = new WebDriverManager( 'chrome', { baseUrl: config.get( 'url' ) } ); - driver = manager.getDriver(); - - helper.clearCookiesAndDeleteLocalStorage( driver ); - } ); - - this.timeout( config.get( 'mochaTimeoutMs' ) ); - - test.it( 'can create new coupon', () => { - const flowArgs = { - baseUrl: config.get( 'url' ), - username: config.get( 'users.admin.username' ), - password: config.get( 'users.admin.password' ) - }; - const storeOwner = new StoreOwnerFlow( driver, flowArgs ); - - const couponPage = storeOwner.openNewCoupon(); - couponPage.setTitle( 'code-' + new Date().getTime().toString() ); - couponPage.setDescription( 'test coupon' ); - - const couponData = couponPage.components.metaBoxCouponData; - const generalPanel = couponData.clickTab( 'General' ); - generalPanel.selectDiscountType( 'Cart Discount' ); - generalPanel.setCouponAmount( '100' ); - - couponPage.publish(); - - assert.eventually.ok( couponPage.hasNotice( 'Coupon updated.' ) ); - } ); - - // take screenshot - test.afterEach( function() { - if ( this.currentTest.state === 'failed' ) { - helper.takeScreenshot( manager, this.currentTest ); - } - } ); - - // quit browser - test.after( () => { - manager.quitBrowser(); - } ); -} ); diff --git a/tests/e2e-tests/wp-admin/wp-admin-order-new.js b/tests/e2e-tests/wp-admin/wp-admin-order-new.js deleted file mode 100644 index 84a6a51f588..00000000000 --- a/tests/e2e-tests/wp-admin/wp-admin-order-new.js +++ /dev/null @@ -1,61 +0,0 @@ -import config from 'config'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import test from 'selenium-webdriver/testing'; -import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; -import { StoreOwnerFlow } from 'wc-e2e-page-objects'; - -chai.use( chaiAsPromised ); -const assert = chai.assert; - -let manager; -let driver; - -test.describe( 'Add New Order Page', function() { - // open browser - test.before( function() { - this.timeout( config.get( 'startBrowserTimeoutMs' ) ); - - manager = new WebDriverManager( 'chrome', { baseUrl: config.get( 'url' ) } ); - driver = manager.getDriver(); - - helper.clearCookiesAndDeleteLocalStorage( driver ); - } ); - - this.timeout( config.get( 'mochaTimeoutMs' ) ); - - test.it( 'can create new order', () => { - const flowArgs = { - baseUrl: config.get( 'url' ), - username: config.get( 'users.admin.username' ), - password: config.get( 'users.admin.password' ) - }; - const storeOwner = new StoreOwnerFlow( driver, flowArgs ); - - const orderPage = storeOwner.openNewOrder(); - const orderData = orderPage.components.metaBoxOrderData; - orderData.selectOrderStatus( 'Processing' ); - orderData.setOrderDate( '2016-12-13' ); - orderData.setOrderDateHour( '18' ); - orderData.setOrderDateMinute( '55' ); - - orderPage.components.metaBoxOrderActions.saveOrder(); - - assert.eventually.ok( orderData.hasOrderStatus( 'Processing' ) ); - - const orderNotes = orderPage.components.metaBoxOrderNotes; - assert.eventually.ok( orderNotes.hasNote( 'Order status changed from Pending payment to Processing.' ) ); - } ); - - // take screenshot - test.afterEach( function() { - if ( this.currentTest.state === 'failed' ) { - helper.takeScreenshot( manager, this.currentTest ); - } - } ); - - // quit browser - test.after( () => { - manager.quitBrowser(); - } ); -} ); diff --git a/tests/e2e-tests/wp-admin/wp-admin-product-new.js b/tests/e2e-tests/wp-admin/wp-admin-product-new.js deleted file mode 100644 index 47db8b20cf9..00000000000 --- a/tests/e2e-tests/wp-admin/wp-admin-product-new.js +++ /dev/null @@ -1,138 +0,0 @@ -import config from 'config'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import test from 'selenium-webdriver/testing'; -import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; -import { WPLogin } from 'wp-e2e-page-objects'; -import { WPAdminProductNew } from 'wc-e2e-page-objects'; - -chai.use( chaiAsPromised ); -const assert = chai.assert; - -let manager; -let driver; - -test.describe( 'Add New Product Page', function() { - // open browser - test.before( function() { - this.timeout( config.get( 'startBrowserTimeoutMs' ) ); - - manager = new WebDriverManager( 'chrome', { baseUrl: config.get( 'url' ) } ); - driver = manager.getDriver(); - - helper.clearCookiesAndDeleteLocalStorage( driver ); - } ); - - this.timeout( config.get( 'mochaTimeoutMs' ) ); - - // login - test.before( () => { - const wpLogin = new WPLogin( driver, { url: manager.getPageUrl( '/wp-login.php' ) } ); - wpLogin.login( config.get( 'users.admin.username' ), config.get( 'users.admin.password' ) ); - } ); - - test.it( 'can create simple virtual product titled "Simple Product" with regular price $9.99', () => { - const product = new WPAdminProductNew( driver, { url: manager.getPageUrl( '/wp-admin/post-new.php?post_type=product' ) } ); - product.setTitle( 'Simple Product' ); - - const productData = product.components.metaBoxProductData; - productData.selectProductType( 'Simple product' ); - productData.checkVirtual(); - - const panelGeneral = productData.clickTab( 'General' ); - panelGeneral.setRegularPrice( '9.99' ); - - product.publish(); - assert.eventually.ok( product.hasNotice( 'Product published.' ) ); - - product.moveToTrash(); - assert.eventually.ok( product.hasNotice( '1 product moved to the Trash.' ) ); - } ); - - test.it( 'can create product with variations', () => { - const product = new WPAdminProductNew( driver, { url: manager.getPageUrl( '/wp-admin/post-new.php?post_type=product' ) } ); - product.setTitle( 'Variable Product with Two Variations' ); - - const productData = product.components.metaBoxProductData; - productData.selectProductType( 'Variable product' ); - - const panelAttributes = productData.clickTab( 'Attributes' ); - panelAttributes.selectAttribute( 'Custom product attribute' ); - - const attr1 = panelAttributes.add(); - assert.eventually.ok( attr1.displayed() ); - attr1.setName( 'attr #1' ); - attr1.checkVisibleOnTheProductPage(); - attr1.checkUsedForVariations(); - attr1.setValue( 'val1 | val2' ); - attr1.toggle(); - - const attr2 = panelAttributes.add(); - assert.eventually.ok( attr2.displayed() ); - attr2.setName( 'attr #2' ); - attr2.checkVisibleOnTheProductPage(); - attr2.checkUsedForVariations(); - attr2.setValue( 'val1 | val2' ); - - const attr3 = panelAttributes.add(); - assert.eventually.ok( attr3.displayed() ); - attr3.setName( 'attr #3' ); - attr3.checkVisibleOnTheProductPage(); - attr3.checkUsedForVariations(); - attr3.setValue( 'val1 | val2' ); - attr3.toggle(); attr2.toggle(); - - panelAttributes.saveAttributes(); - - const panelVaritions = productData.clickTab( 'Variations' ); - panelVaritions.selectAction( 'Create variations from all attributes' ); - panelVaritions.go(); - - // We start at two because of a new message introduced at the top of the panel. - const var1 = panelVaritions.getRow( 2 ); - var1.toggle(); - var1.checkEnabled(); - var1.checkVirtual(); - var1.setRegularPrice( '9.99' ); - - const var2 = panelVaritions.getRow( 3 ); - var2.toggle(); - var2.checkEnabled(); - var2.checkVirtual(); - var2.setRegularPrice( '11.99' ); - - const var3 = panelVaritions.getRow( 4 ); - var3.toggle(); - var3.checkEnabled(); - var3.checkManageStock(); - var3.setRegularPrice( '20' ); - var3.setWeight( '200' ); - var3.setDimensionLength( '10' ); - var3.setDimensionWidth( '20' ); - var3.setDimensionHeight( '15' ); - - panelVaritions.saveChanges(); - - helper.scrollUp( driver ); - helper.scrollUp( driver ); - helper.scrollUp( driver ); - - product.publish(); - assert.eventually.ok( product.hasNotice( 'Product published.' ) ); - - product.moveToTrash(); - assert.eventually.ok( product.hasNotice( '1 product moved to the Trash.' ) ); - } ); - - // take screenshot - test.afterEach( function() { - if ( this.currentTest.state === 'failed' ) { - helper.takeScreenshot( manager, this.currentTest ); - } - } ); - - // quit browser - test.after( () => { - manager.quitBrowser(); - } ); -} ); diff --git a/tests/e2e-tests/wp-admin/wp-admin-wc-settings-general.js b/tests/e2e-tests/wp-admin/wp-admin-wc-settings-general.js deleted file mode 100644 index 8b40ca58668..00000000000 --- a/tests/e2e-tests/wp-admin/wp-admin-wc-settings-general.js +++ /dev/null @@ -1,80 +0,0 @@ -import config from 'config'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import test from 'selenium-webdriver/testing'; -import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; -import { WPLogin } from 'wp-e2e-page-objects'; -import { WPAdminWCSettingsGeneral } from 'wc-e2e-page-objects'; - -chai.use( chaiAsPromised ); -const assert = chai.assert; - -let manager; -let driver; - -test.describe( 'WooCommerce General Settings', function() { - // open browser - test.before( function() { - this.timeout( config.get( 'startBrowserTimeoutMs' ) ); - - manager = new WebDriverManager( 'chrome', { baseUrl: config.get( 'url' ) } ); - driver = manager.getDriver(); - - helper.clearCookiesAndDeleteLocalStorage( driver ); - } ); - - this.timeout( config.get( 'mochaTimeoutMs' ) ); - - // login - test.before( () => { - const wpLogin = new WPLogin( driver, { url: manager.getPageUrl( '/wp-login.php' ) } ); - wpLogin.login( config.get( 'users.admin.username' ), config.get( 'users.admin.password' ) ); - } ); - - test.it( 'can update settings', () => { - const settingsArgs = { url: manager.getPageUrl( '/wp-admin/admin.php?page=wc-settings&tab=general' ) }; - const settings = new WPAdminWCSettingsGeneral( driver, settingsArgs ); - - assert.eventually.ok( settings.hasActiveTab( 'General' ) ); - - // Set selling location to all countries first, so we can choose california - // as base location. - settings.selectSellingLocation( 'Sell to all countries' ); - settings.saveChanges(); - assert.eventually.ok( settings.hasNotice( 'Your settings have been saved.' ) ); - - // Set base location with state CA. - settings.selectBaseLocation( 'california', 'United States (US) — California' ); - settings.saveChanges(); - assert.eventually.ok( settings.hasNotice( 'Your settings have been saved.' ) ); - - // Set selling location to specific countries first, so we can choose - // U.S as base location (without state). This will makes specific - // countries option appears. - settings.selectSellingLocation( 'Sell to specific countries' ); - settings.removeChoiceInSellToSpecificCountries( 'United States (US)' ); - settings.setSellToSpecificCountries( 'united states', 'United States (US)' ); - settings.saveChanges(); - assert.eventually.ok( settings.hasNotice( 'Your settings have been saved.' ) ); - - // Set currency options. - settings.setThousandSeparator( ',' ); - settings.setDecimalSeparator( '.' ); - settings.setNumberOfDecimals( '2' ); - - settings.saveChanges(); - assert.eventually.ok( settings.hasNotice( 'Your settings have been saved.' ) ); - } ); - - // take screenshot - test.afterEach( function() { - if ( this.currentTest.state === 'failed' ) { - helper.takeScreenshot( manager, this.currentTest ); - } - } ); - - // quit browser - test.after( () => { - manager.quitBrowser(); - } ); -} ); diff --git a/tests/e2e-tests/wp-admin/wp-admin-wc-settings-products-downloadable.js b/tests/e2e-tests/wp-admin/wp-admin-wc-settings-products-downloadable.js deleted file mode 100644 index 718fa63d1d6..00000000000 --- a/tests/e2e-tests/wp-admin/wp-admin-wc-settings-products-downloadable.js +++ /dev/null @@ -1,65 +0,0 @@ -import config from 'config'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import test from 'selenium-webdriver/testing'; -import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; -import { WPLogin } from 'wp-e2e-page-objects'; -import { WPAdminWCSettingsProductsDownloadable } from 'wc-e2e-page-objects'; - -chai.use( chaiAsPromised ); -const assert = chai.assert; - -let manager; -let driver; - -test.describe( 'WooCommerce Products > Downloadable Products Settings', function() { - // open browser - test.before( function() { - this.timeout( config.get( 'startBrowserTimeoutMs' ) ); - - manager = new WebDriverManager( 'chrome', { baseUrl: config.get( 'url' ) } ); - driver = manager.getDriver(); - - helper.clearCookiesAndDeleteLocalStorage( driver ); - } ); - - this.timeout( config.get( 'mochaTimeoutMs' ) ); - - // login - test.before( () => { - const wpLogin = new WPLogin( driver, { url: manager.getPageUrl( '/wp-login.php' ) } ); - wpLogin.login( config.get( 'users.admin.username' ), config.get( 'users.admin.password' ) ); - } ); - - test.it( 'can update settings', () => { - const settingsArgs = { url: manager.getPageUrl( '/wp-admin/admin.php?page=wc-settings&tab=products§ion=downloadable' ) }; - const settings = new WPAdminWCSettingsProductsDownloadable( driver, settingsArgs ); - - assert.eventually.ok( settings.hasActiveTab( 'Products' ) ); - assert.eventually.ok( settings.hasActiveSubTab( 'Downloadable products' ) ); - - settings.selectFileDownloadMethod( 'Redirect only' ); - settings.checkDownloadsRequireLogin(); - settings.checkGrantAccessAfterPayment(); - settings.saveChanges(); - assert.eventually.ok( settings.hasNotice( 'Your settings have been saved.' ) ); - - settings.selectFileDownloadMethod( 'Force downloads' ); - settings.uncheckDownloadsRequireLogin(); - settings.uncheckGrantAccessAfterPayment(); - settings.saveChanges(); - assert.eventually.ok( settings.hasNotice( 'Your settings have been saved.' ) ); - } ); - - // take screenshot - test.afterEach( function() { - if ( this.currentTest.state === 'failed' ) { - helper.takeScreenshot( manager, this.currentTest ); - } - } ); - - // quit browser - test.after( () => { - manager.quitBrowser(); - } ); -} ); diff --git a/tests/e2e-tests/wp-admin/wp-admin-wc-settings-tax.js b/tests/e2e-tests/wp-admin/wp-admin-wc-settings-tax.js deleted file mode 100644 index a5113bf23d2..00000000000 --- a/tests/e2e-tests/wp-admin/wp-admin-wc-settings-tax.js +++ /dev/null @@ -1,109 +0,0 @@ -import config from 'config'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import test from 'selenium-webdriver/testing'; -import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver'; -import { WPLogin } from 'wp-e2e-page-objects'; -import { WPAdminWCSettingsTax, WPAdminWCSettingsTaxRates } from 'wc-e2e-page-objects'; - -chai.use( chaiAsPromised ); -const assert = chai.assert; - -let manager; -let driver; - -test.describe( 'WooCommerce Tax Settings', function() { - // open browser - test.before( function() { - this.timeout( config.get( 'startBrowserTimeoutMs' ) ); - - manager = new WebDriverManager( 'chrome', { baseUrl: config.get( 'url' ) } ); - driver = manager.getDriver(); - - helper.clearCookiesAndDeleteLocalStorage( driver ); - } ); - - this.timeout( config.get( 'mochaTimeoutMs' ) ); - - // login - test.before( () => { - const wpLogin = new WPLogin( driver, { url: manager.getPageUrl( '/wp-login.php' ) } ); - wpLogin.login( config.get( 'users.admin.username' ), config.get( 'users.admin.password' ) ); - } ); - - test.it( 'can set tax options', () => { - const settingsArgs = { url: manager.getPageUrl( '/wp-admin/admin.php?page=wc-settings&tab=tax' ) }; - const settings = new WPAdminWCSettingsTax( driver, settingsArgs ); - - assert.eventually.ok( settings.hasActiveTab( 'Tax' ) ); - - settings.selectPricesEnteredWithNoTax(); - settings.selectCalculateTaxBasedOn( 'Customer shipping address' ); - settings.selectShippingTaxClass( 'Standard' ); - settings.uncheckRounding(); - settings.selectDisplayPricesInTheShop( 'Excluding tax' ); - settings.selectDisplayPricesDuringCartAndCheckout( 'Including tax' ); - settings.selectDisplayTaxTotals( 'As a single total' ); - - settings.saveChanges(); - assert.eventually.ok( settings.hasNotice( 'Your settings have been saved.' ) ); - } ); - - test.it( 'can add tax classes', () => { - const settingsArgs = { url: manager.getPageUrl( '/wp-admin/admin.php?page=wc-settings&tab=tax' ) }; - const settings = new WPAdminWCSettingsTax( driver, settingsArgs ); - - settings.removeAdditionalTaxClasses(); - settings.saveChanges(); - - settings.addAdditionalTaxClass( 'Fancy' ); - settings.saveChanges(); - - assert.eventually.ok( settings.hasSubTab( 'Fancy rates' ) ); - } ); - - test.it( 'can set rate settings', () => { - const settingsArgs = { url: manager.getPageUrl( '/wp-admin/admin.php?page=wc-settings&tab=tax§ion=fancy' ) }; - const settings = new WPAdminWCSettingsTaxRates( driver, settingsArgs ); - - settings.insertRow(); - settings.setCountryCode( 1, 'US' ); - settings.setStateCode( 1, 'CA' ); - settings.setRate( 1, '7.5' ); - settings.setTaxName( 1, 'CA State Tax' ); - - settings.insertRow(); - settings.setCountryCode( 2, 'US' ); - settings.setRate( 2, '1.5' ); - settings.setPriority( 2, '2' ); - settings.setTaxName( 2, 'Federal Tax' ); - settings.uncheckShipping( 2 ); - settings.saveChanges(); - - settings.removeRow( 2 ); - settings.saveChanges(); - assert.eventually.ifError( helper.isEventuallyPresentAndDisplayed( driver, settings.getSelector( 2 ), 1000 ) ); - } ); - - test.it( 'can remove tax classes', () => { - const settingsArgs = { url: manager.getPageUrl( '/wp-admin/admin.php?page=wc-settings&tab=tax' ) }; - const settings = new WPAdminWCSettingsTax( driver, settingsArgs ); - - settings.removeAdditionalTaxClass( 'Fancy' ); - settings.saveChanges(); - - assert.eventually.ifError( settings.hasSubTab( 'Fancy rates' ) ); - } ); - - // take screenshot - test.afterEach( function() { - if ( this.currentTest.state === 'failed' ) { - helper.takeScreenshot( manager, this.currentTest ); - } - } ); - - // quit browser - test.after( () => { - manager.quitBrowser(); - } ); -} ); diff --git a/tests/framework/helpers/class-wc-helper-order.php b/tests/framework/helpers/class-wc-helper-order.php index 720c2773155..3807f213940 100644 --- a/tests/framework/helpers/class-wc-helper-order.php +++ b/tests/framework/helpers/class-wc-helper-order.php @@ -1,4 +1,9 @@ '', ); - $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; // Required, else wc_create_order throws an exception + $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; // Required, else wc_create_order throws an exception. $order = wc_create_order( $order_data ); - // Add order products + // Add order products. $item = new WC_Order_Item_Product(); $item->set_props( array( @@ -69,7 +74,7 @@ class WC_Helper_Order { $item->save(); $order->add_item( $item ); - // Set billing address + // Set billing address. $order->set_billing_first_name( 'Jeroen' ); $order->set_billing_last_name( 'Sormani' ); $order->set_billing_company( 'WooCompany' ); @@ -77,12 +82,12 @@ class WC_Helper_Order { $order->set_billing_address_2( '' ); $order->set_billing_city( 'WooCity' ); $order->set_billing_state( 'NY' ); - $order->set_billing_postcode( '123456' ); + $order->set_billing_postcode( '12345' ); $order->set_billing_country( 'US' ); $order->set_billing_email( 'admin@example.org' ); $order->set_billing_phone( '555-32123' ); - // Add shipping costs + // Add shipping costs. $shipping_taxes = WC_Tax::calc_shipping_tax( '10', WC_Tax::get_shipping_tax_rates() ); $rate = new WC_Shipping_Rate( 'flat_rate_shipping', 'Flat rate shipping', '10', $shipping_taxes, 'flat_rate' ); $item = new WC_Order_Item_Shipping(); @@ -99,11 +104,11 @@ class WC_Helper_Order { } $order->add_item( $item ); - // Set payment gateway + // Set payment gateway. $payment_gateways = WC()->payment_gateways->payment_gateways(); $order->set_payment_method( $payment_gateways['bacs'] ); - // Set totals + // Set totals. $order->set_shipping_total( 10 ); $order->set_discount_total( 0 ); $order->set_discount_tax( 0 ); diff --git a/tests/framework/helpers/class-wc-helper-product.php b/tests/framework/helpers/class-wc-helper-product.php index c07ecec03b7..6a6aaab680d 100644 --- a/tests/framework/helpers/class-wc-helper-product.php +++ b/tests/framework/helpers/class-wc-helper-product.php @@ -116,7 +116,7 @@ class WC_Helper_Product { ) ); - $attributes = array(); + $attributes = array(); $attribute = new WC_Product_Attribute(); $attribute_data = self::create_attribute( 'size', array( 'small', 'large', 'huge' ) ); @@ -183,7 +183,7 @@ class WC_Helper_Product { ); $variation_3->set_attributes( array( - 'pa_size' => 'huge', + 'pa_size' => 'huge', 'pa_colour' => 'red', 'pa_number' => '0', ) @@ -200,7 +200,7 @@ class WC_Helper_Product { ); $variation_4->set_attributes( array( - 'pa_size' => 'huge', + 'pa_size' => 'huge', 'pa_colour' => 'red', 'pa_number' => '2', ) diff --git a/tests/unit-tests/cart/cart.php b/tests/unit-tests/cart/cart.php index a31068c9931..ed35df182e6 100644 --- a/tests/unit-tests/cart/cart.php +++ b/tests/unit-tests/cart/cart.php @@ -62,6 +62,10 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { 'cost' => '9.59', ); update_option( 'woocommerce_flat_rate_settings', $flat_rate_settings ); + // Set an address so that shipping can be calculated. + add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) ); + add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) ); + add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) ); WC()->cart->add_to_cart( $product->get_id(), 1 ); WC()->cart->add_discount( $coupon->get_code() ); @@ -172,6 +176,11 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { update_option( 'woocommerce_calc_taxes', 'yes' ); update_option( 'woocommerce_tax_round_at_subtotal', 'yes' ); + // Set an address so that shipping can be calculated. + add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) ); + add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) ); + add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) ); + $tax_rate = array( 'tax_rate_country' => '', 'tax_rate_state' => '', @@ -260,7 +269,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { update_option( 'woocommerce_calc_taxes', 'yes' ); update_option( 'woocommerce_tax_round_at_subtotal', 'yes' ); - $tax_rate = array( + $tax_rate = array( 'tax_rate_country' => '', 'tax_rate_state' => '', 'tax_rate' => '24.0000', @@ -273,7 +282,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { ); WC_Tax::_insert_tax_rate( $tax_rate ); - $tax_rate = array( + $tax_rate = array( 'tax_rate_country' => '', 'tax_rate_state' => '', 'tax_rate' => '24.0000', @@ -567,7 +576,8 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { $full_coupon->set_amount( 100 ); $full_coupon->save(); - add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_gb_shipping' ) ); + add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_gb_country' ) ); + add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_gb_postcode' ) ); WC()->cart->add_to_cart( $product->get_id(), 1 ); // Test in store location with no coupon. @@ -604,8 +614,11 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { WC()->cart->remove_coupons(); WC()->cart->empty_cart(); - remove_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_gb_shipping' ) ); - add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_shipping' ) ); + remove_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_gb_country' ) ); + remove_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_gb_postcode' ) ); + add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) ); + add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) ); + add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) ); WC()->cart->add_to_cart( $product->get_id(), 1 ); // Test out of store location with no coupon. @@ -710,7 +723,8 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { $full_coupon->set_amount( 100 ); $full_coupon->save(); - add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_gb_shipping' ) ); + add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_gb_country' ) ); + add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_gb_postcode' ) ); WC()->cart->add_to_cart( $product->get_id(), 1 ); // Test in store location with no coupon. @@ -747,8 +761,11 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { WC()->cart->remove_coupons(); WC()->cart->empty_cart(); - remove_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_gb_shipping' ) ); - add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_shipping' ) ); + remove_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_gb_country' ) ); + remove_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_gb_postcode' ) ); + add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) ); + add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) ); + add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) ); WC()->cart->add_to_cart( $product->get_id(), 1 ); // Test out of store location with no coupon. @@ -851,7 +868,9 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { $full_coupon->set_amount( 100 ); $full_coupon->save(); - add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_shipping' ) ); + add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) ); + add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) ); + add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) ); WC()->cart->add_to_cart( $product->get_id(), 1 ); // Test out of store location with no coupon. @@ -895,10 +914,21 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { * @param string $country Country code. * @return string */ - public function force_customer_gb_shipping( $country ) { + public function force_customer_gb_country( $country ) { return 'GB'; } + /** + * Helper that can be hooked to a filter to force the customer's shipping postal code to be ANN NAA. + * + * @since 3.10.0 + * @param string $postcode Postal code.. + * @return string + */ + public function force_customer_gb_postcode( $postcode ) { + return 'ANN NAA'; + } + /** * Helper that can be hooked to a filter to force the customer's shipping country to be US. * @@ -906,10 +936,32 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { * @param string $country Country code. * @return string */ - public function force_customer_us_shipping( $country ) { + public function force_customer_us_country( $country ) { return 'US'; } + /** + * Helper that can be hooked to a filter to force the customer's shipping state to be NY. + * + * @since 3.10.0 + * @param string $state State code. + * @return string + */ + public function force_customer_us_state( $state ) { + return 'NY'; + } + + /** + * Helper that can be hooked to a filter to force the customer's shipping postal code to be 12345. + * + * @since 3.10.0 + * @param string $postcode Postal code. + * @return string + */ + public function force_customer_us_postcode( $postcode ) { + return '12345'; + } + /** * Test a rounding issue on prices that are entered inclusive tax and shipping is used. * See: #17970. @@ -932,6 +984,11 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { update_option( 'woocommerce_prices_include_tax', 'yes' ); update_option( 'woocommerce_calc_taxes', 'yes' ); + // Set an address so that shipping can be calculated. + add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) ); + add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) ); + add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) ); + // 19% tax. $tax_rate = array( 'tax_rate_country' => '', @@ -1487,6 +1544,11 @@ class WC_Tests_Cart extends WC_Unit_Test_Case { // Add product to cart. WC()->cart->add_to_cart( $product->get_id(), 1 ); + // Set an address so that shipping can be calculated. + add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) ); + add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) ); + add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) ); + // Set the flat_rate shipping method. WC()->session->set( 'chosen_shipping_methods', array( 'flat_rate' ) ); WC()->cart->calculate_totals(); diff --git a/tests/unit-tests/checkout/checkout.php b/tests/unit-tests/checkout/checkout.php new file mode 100644 index 00000000000..f806ee4bdb1 --- /dev/null +++ b/tests/unit-tests/checkout/checkout.php @@ -0,0 +1,132 @@ +cart->empty_cart(); + } + + /** + * Setup for tests. + */ + public function setUp() { + parent::setUp(); + WC()->cart->empty_cart(); + } + + /** + * Test if order can be created when a coupon with usage limit is applied. + * + * @throws Exception When unable to create order. + */ + public function test_create_order_with_limited_coupon() { + $coupon_code = 'coupon4one'; + $coupon_data_store = WC_Data_Store::load( 'coupon' ); + $coupon = WC_Helper_Coupon::create_coupon( + $coupon_code, + array( 'usage_limit' => 1 ) + ); + $product = WC_Helper_Product::create_simple_product( true ); + WC()->cart->add_to_cart( $product->get_id(), 1 ); + WC()->cart->add_discount( $coupon->get_code() ); + $checkout = WC_Checkout::instance(); + $order_id = $checkout->create_order( + array( + 'billing_email' => 'a@b.com', + 'payment_method' => 'dummy_payment_gateway', + ) + ); + $this->assertNotWPError( $order_id ); + $order = new WC_Order( $order_id ); + $coupon_held_key = $order->get_data_store()->get_coupon_held_keys( $order ); + $this->assertEquals( count( $coupon_held_key ), 1 ); + $this->assertEquals( array_keys( $coupon_held_key )[0], $coupon->get_id() ); + $this->assertEquals( strpos( $coupon_held_key[ $coupon->get_id() ], '_coupon_held_' ), 0 ); + $this->assertEquals( $coupon_data_store->get_tentative_usage_count( $coupon->get_id() ), 1 ); + + WC()->cart->empty_cart(); + WC()->cart->add_to_cart( $product->get_id(), 1 ); + WC()->cart->add_discount( $coupon->get_code() ); + $order2_id = $checkout->create_order( + array( + 'billing_email' => 'a@c.com', + 'payment_method' => 'dummy_payment_gateway', + ) + ); + $this->assertWPError( $order2_id ); + $this->assertEquals( $coupon_data_store->get_tentative_usage_count( $coupon->get_id() ), 1 ); + } + + /** + * Test when order is created with multiple coupon when usage limit for one is exhausted. + * + * @throws Exception When unable to create an order. + */ + public function test_create_order_with_multiple_limited_coupons() { + $coupon_code1 = 'coupon1'; + $coupon_code2 = 'coupon2'; + $coupon_data_store = WC_Data_Store::load( 'coupon' ); + + $coupon1 = WC_Helper_Coupon::create_coupon( + $coupon_code1, + array( 'usage_limit' => 2 ) + ); + $coupon2 = WC_Helper_Coupon::create_coupon( + $coupon_code2, + array( 'usage_limit' => 1 ) + ); + $product = WC_Helper_Product::create_simple_product( true ); + WC()->cart->add_to_cart( $product->get_id(), 1 ); + WC()->cart->add_discount( $coupon_code1 ); + WC()->cart->add_discount( $coupon_code2 ); + $checkout = WC_Checkout::instance(); + $order_id1 = $checkout->create_order( + array( + 'billing_email' => 'a@b.com', + 'payment_method' => 'dummy_payment_gateway', + ) + ); + + $this->assertNotWPError( $order_id1 ); + $this->assertEquals( $coupon_data_store->get_tentative_usage_count( $coupon1->get_id() ), 1 ); + $this->assertEquals( $coupon_data_store->get_tentative_usage_count( $coupon2->get_id() ), 1 ); + + WC()->cart->empty_cart(); + WC()->cart->add_to_cart( $product->get_id(), 1 ); + WC()->cart->add_discount( $coupon_code1 ); + WC()->cart->add_discount( $coupon_code2 ); + + $order2_id = $checkout->create_order( + array( + 'billing_email' => 'a@b.com', + 'payment_method' => 'dummy_payment_gateway', + ) + ); + + $this->assertWPError( $order2_id ); + $this->assertEquals( $coupon_data_store->get_tentative_usage_count( $coupon1->get_id() ), 1 ); + $this->assertEquals( $coupon_data_store->get_tentative_usage_count( $coupon2->get_id() ), 1 ); + } + + /** + * Helper function to return 0.01. + * + * @return float + */ + public function __return_0_01() { + return 0.01; + } + +} diff --git a/tests/unit-tests/coupon/coupon.php b/tests/unit-tests/coupon/coupon.php index 75922d17e02..e5a2dda5ec4 100644 --- a/tests/unit-tests/coupon/coupon.php +++ b/tests/unit-tests/coupon/coupon.php @@ -1,4 +1,9 @@ customer->set_shipping_country( 'US' ); + WC()->customer->set_shipping_state( 'NY' ); + WC()->customer->set_shipping_postcode( '12345' ); + } + + /** + * Cleans up after the test class. + */ public function tearDown() { WC()->cart->empty_cart(); WC()->cart->remove_coupons(); @@ -53,7 +73,7 @@ class WC_Tests_Coupon extends WC_Unit_Test_Case { $test_coupon = new WC_Coupon( (string) $coupon_2->get_id() ); $this->assertEquals( $coupon_2->get_id(), $test_coupon->get_id() ); - // Test getting a coupon by coupon object + // Test getting a coupon by coupon object. $test_coupon = new WC_Coupon( $coupon_1 ); $this->assertEquals( $test_coupon->get_id(), $coupon_1->get_id() ); } @@ -65,13 +85,13 @@ class WC_Tests_Coupon extends WC_Unit_Test_Case { */ public function test_add_discount() { - // Create coupon + // Create coupon. $coupon = WC_Helper_Coupon::create_coupon(); - // Add coupon, test return statement + // Add coupon, test return statement. $this->assertTrue( WC()->cart->add_discount( $coupon->get_code() ) ); - // Test if total amount of coupons is 1 + // Test if total amount of coupons is 1. $this->assertEquals( 1, count( WC()->cart->get_applied_coupons() ) ); } @@ -82,16 +102,16 @@ class WC_Tests_Coupon extends WC_Unit_Test_Case { */ public function test_add_discount_duplicate() { - // Create coupon + // Create coupon. $coupon = WC_Helper_Coupon::create_coupon(); - // Add coupon + // Add coupon. $this->assertTrue( WC()->cart->add_discount( $coupon->get_code() ) ); - // Add coupon again, test return statement + // Add coupon again, test return statement. $this->assertFalse( WC()->cart->add_discount( $coupon->get_code() ) ); - // Test if total amount of coupons is 1 + // Test if total amount of coupons is 1. $this->assertEquals( 1, count( WC()->cart->get_applied_coupons() ) ); } @@ -102,30 +122,30 @@ class WC_Tests_Coupon extends WC_Unit_Test_Case { */ public function test_fixed_cart_discount() { - // Create product + // Create product. $product = WC_Helper_Product::create_simple_product(); $product->set_regular_price( 10 ); $product->save(); - // Create coupon + // Create coupon. $coupon = WC_Helper_Coupon::create_coupon(); update_post_meta( $coupon->get_id(), 'discount_type', 'fixed_cart' ); update_post_meta( $coupon->get_id(), 'coupon_amount', '5' ); - // Create a flat rate method + // Create a flat rate method. WC_Helper_Shipping::create_simple_flat_rate(); - // Add product to cart + // Add product to cart. WC()->cart->add_to_cart( $product->get_id(), 1 ); - // Add coupon + // Add coupon. WC()->cart->add_discount( $coupon->get_code() ); - // Set the flat_rate shipping method + // Set the flat_rate shipping method. WC()->session->set( 'chosen_shipping_methods', array( 'flat_rate' ) ); WC()->cart->calculate_totals(); - // Test if the cart total amount is equal 15 + // Test if the cart total amount is equal 15. $this->assertEquals( 15, WC()->cart->total ); } @@ -136,33 +156,33 @@ class WC_Tests_Coupon extends WC_Unit_Test_Case { */ public function test_fixed_product_discount() { - // Create product + // Create product. $product = WC_Helper_Product::create_simple_product(); $product->set_regular_price( 10 ); $product->save(); - // Create coupon + // Create coupon. $coupon = WC_Helper_Coupon::create_coupon(); update_post_meta( $coupon->get_id(), 'discount_type', 'fixed_product' ); update_post_meta( $coupon->get_id(), 'coupon_amount', '5' ); - // Create a flat rate method - $10 + // Create a flat rate method - $10. WC_Helper_Shipping::create_simple_flat_rate(); - // Add fee - $10 + // Add fee - $10. WC_Helper_Fee::add_cart_fee(); - // Add product to cart + // Add product to cart. WC()->cart->add_to_cart( $product->get_id(), 1 ); - // Add coupon + // Add coupon. WC()->cart->add_discount( $coupon->get_code() ); - // Set the flat_rate shipping method + // Set the flat_rate shipping method. WC()->session->set( 'chosen_shipping_methods', array( 'flat_rate' ) ); WC()->cart->calculate_totals(); - // Test if the cart total amount is equal 25 + // Test if the cart total amount is equal 25. $this->assertEquals( 25, WC()->cart->total ); } @@ -173,33 +193,33 @@ class WC_Tests_Coupon extends WC_Unit_Test_Case { */ public function test_percent_discount() { - // Create product + // Create product. $product = WC_Helper_Product::create_simple_product(); $product->set_regular_price( 10 ); $product->save(); - // Create coupon + // Create coupon. $coupon = WC_Helper_Coupon::create_coupon(); update_post_meta( $coupon->get_id(), 'discount_type', 'percent' ); update_post_meta( $coupon->get_id(), 'coupon_amount', '5' ); - // Create a flat rate method + // Create a flat rate method. WC_Helper_Shipping::create_simple_flat_rate(); - // Add fee + // Add fee. WC_Helper_Fee::add_cart_fee(); - // Add product to cart + // Add product to cart. WC()->cart->add_to_cart( $product->get_id(), 1 ); - // Add coupon + // Add coupon. WC()->cart->add_discount( $coupon->get_code() ); - // Set the flat_rate shipping method + // Set the flat_rate shipping method. WC()->session->set( 'chosen_shipping_methods', array( 'flat_rate' ) ); WC()->cart->calculate_totals(); - // Test if the cart total amount is equal 29.5 + // Test if the cart total amount is equal 29.5. $this->assertEquals( 29.5, WC()->cart->total ); } @@ -229,12 +249,12 @@ class WC_Tests_Coupon extends WC_Unit_Test_Case { * Test an item limit for percent discounts. */ public function test_percent_discount_item_limit() { - // Create product + // Create product. $product = WC_Helper_Product::create_simple_product(); update_post_meta( $product->get_id(), '_price', '10' ); update_post_meta( $product->get_id(), '_regular_price', '10' ); - // Create coupon + // Create coupon. $coupon = WC_Helper_Coupon::create_coupon( 'dummycoupon', array( @@ -258,16 +278,19 @@ class WC_Tests_Coupon extends WC_Unit_Test_Case { $this->assertEquals( 19.5, WC()->cart->total ); } + /** + * Test the coupon's item limit. + */ public function test_custom_discount_item_limit() { // Register custom discount type. WC_Helper_Coupon::register_custom_type( __FUNCTION__ ); - // Create product + // Create product. $product = WC_Helper_Product::create_simple_product(); update_post_meta( $product->get_id(), '_price', '10' ); update_post_meta( $product->get_id(), '_regular_price', '10' ); - // Create coupon + // Create coupon. $coupon = WC_Helper_Coupon::create_coupon( 'dummycoupon', array( diff --git a/tests/unit-tests/customer/customer-download-log.php b/tests/unit-tests/customer/customer-download-log.php index df327447097..8e9a7815354 100644 --- a/tests/unit-tests/customer/customer-download-log.php +++ b/tests/unit-tests/customer/customer-download-log.php @@ -30,7 +30,7 @@ class WC_Tests_Customer_Download_Log extends WC_Unit_Test_Case { */ public function test_get_timestamp() { $object = new WC_Customer_Download_Log(); - $set_to = current_time( 'timestamp', true ); + $set_to = time(); // Convert timestamp to WC_DateTime using ISO 8601 for PHP 5.2 compat. $dt_str = date( 'c', $set_to ); @@ -84,7 +84,7 @@ class WC_Tests_Customer_Download_Log extends WC_Unit_Test_Case { $download_1->save(); // Create download log. - $timestamp = current_time( 'timestamp', true ); + $timestamp = time(); // Convert timestamp to WC_DateTime using ISO 8601 for PHP 5.2 compat. $dt_str = date( 'c', $timestamp ); diff --git a/tests/unit-tests/geolocation/class-wc-tests-geolite-integration.php b/tests/unit-tests/geolocation/class-wc-tests-geolite-integration.php deleted file mode 100644 index 08a277503f2..00000000000 --- a/tests/unit-tests/geolocation/class-wc-tests-geolite-integration.php +++ /dev/null @@ -1,40 +0,0 @@ -assertEquals( 'US', $geolite->get_country_iso( $ipv4 ) ); - - // Check for IPv6. - $this->assertEquals( 'US', $geolite->get_country_iso( $ipv6 ) ); - - // Check for non-valid IP. - $this->assertEquals( '', $geolite->get_country_iso( 'foobar' ) ); - } -} diff --git a/tests/unit-tests/integrations/class-wc-tests-integrations.php b/tests/unit-tests/integrations/class-wc-tests-integrations.php index 083a873f11f..1adc9aff493 100644 --- a/tests/unit-tests/integrations/class-wc-tests-integrations.php +++ b/tests/unit-tests/integrations/class-wc-tests-integrations.php @@ -30,8 +30,8 @@ class WC_Tests_Integrations extends WC_Unit_Test_Case { */ public function test_filter() { $integrations = new WC_Integrations(); - $this->assertEquals( array(), $integrations->integrations ); - $this->assertEquals( array(), $integrations->get_integrations() ); + $this->assertArrayHasKey( 'maxmind_geolocation', $integrations->integrations ); + $this->assertArrayHasKey( 'maxmind_geolocation', $integrations->get_integrations() ); require_once dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'class-dummy-integration.php'; diff --git a/tests/unit-tests/integrations/maxmind-geolocation/class-wc-tests-maxmind-database.php b/tests/unit-tests/integrations/maxmind-geolocation/class-wc-tests-maxmind-database.php new file mode 100644 index 00000000000..aba5a35a1af --- /dev/null +++ b/tests/unit-tests/integrations/maxmind-geolocation/class-wc-tests-maxmind-database.php @@ -0,0 +1,146 @@ +http_responder = array( $this, 'mock_http_responses' ); + } + + /** + * Tests that the database path filters work as intended. + * + * @expectedDeprecated woocommerce_geolocation_local_database_path + */ + public function test_database_path_filters() { + $database_service = new WC_Integration_MaxMind_Database_Service( '' ); + + $path = $database_service->get_database_path(); + $this->assertEquals( WP_CONTENT_DIR . '/uploads/woocommerce_uploads/' . WC_Integration_MaxMind_Database_Service::DATABASE . WC_Integration_MaxMind_Database_Service::DATABASE_EXTENSION, $path ); + + add_filter( 'woocommerce_geolocation_local_database_path', array( $this, 'filter_database_path_deprecated' ), 1, 2 ); + $path = $database_service->get_database_path(); + remove_filter( 'woocommerce_geolocation_local_database_path', array( $this, 'filter_database_path_deprecated' ), 1 ); + + $this->assertEquals( '/deprecated_filter', $path ); + + add_filter( 'woocommerce_geolocation_local_database_path', array( $this, 'filter_database_path' ) ); + $path = $database_service->get_database_path(); + remove_filter( 'woocommerce_geolocation_local_database_path', array( $this, 'filter_database_path' ) ); + + $this->assertEquals( '/filter', $path ); + + // Now perform any tests with a database file prefix. + $database_service = new WC_Integration_MaxMind_Database_Service( 'testing' ); + + $path = $database_service->get_database_path(); + $this->assertEquals( WP_CONTENT_DIR . '/uploads/woocommerce_uploads/testing-' . WC_Integration_MaxMind_Database_Service::DATABASE . WC_Integration_MaxMind_Database_Service::DATABASE_EXTENSION, $path ); + } + + /** + * Tests that the database download works as expected. + */ + public function test_download_database_works() { + $database_service = new WC_Integration_MaxMind_Database_Service( '' ); + $expected_database = '/tmp/GeoLite2-Country_20200100/GeoLite2-Country.mmdb'; + + $result = $database_service->download_database( 'testing_license' ); + + $this->assertEquals( $expected_database, $result ); + + // Remove the downloaded file and folder. + unlink( $expected_database ); + rmdir( dirname( $expected_database ) ); + } + + /** + * Tests the that database download wraps the download and extraction errors. + */ + public function test_download_database_wraps_errors() { + $database_service = new WC_Integration_MaxMind_Database_Service( '' ); + + $result = $database_service->download_database( 'invalid_license' ); + + $this->assertWPError( $result ); + $this->assertEquals( 'woocommerce_maxmind_geolocation_database_license_key', $result->get_error_code() ); + + $result = $database_service->download_database( 'generic_error' ); + + $this->assertWPError( $result ); + $this->assertEquals( 'woocommerce_maxmind_geolocation_database_download', $result->get_error_code() ); + + $result = $database_service->download_database( 'archive_error' ); + + $this->assertWPError( $result ); + $this->assertEquals( 'woocommerce_maxmind_geolocation_database_archive', $result->get_error_code() ); + } + + /** + * Hook for the deprecated database path filter. + * + * @param string $database_path The path to the database file. + * @param string $deprecated Deprecated since 3.4.0. + * @return string + */ + public function filter_database_path_deprecated( $database_path, $deprecated ) { + return '/deprecated_filter'; + } + + /** + * Hook for the database path filter. + * + * @param string $database_path The path to the database file. + * @return string + */ + public function filter_database_path( $database_path ) { + return '/filter'; + } + + /** + * Helper method to define mocked HTTP responses using WP_HTTP_TestCase. + * Thanks to WP_HTTP_TestCase, it is not necessary to perform a regular request + * to an external server which would significantly slow down the tests. + * + * This function is called by WP_HTTP_TestCase::http_request_listner(). + * + * @param array $request Request arguments. + * @param string $url URL of the request. + * + * @return array|WP_Error|false mocked response, error, or false to let WP perform a regular request. + */ + protected function mock_http_responses( $request, $url ) { + $mocked_response = false; + + if ( 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=testing_license&suffix=tar.gz' === $url ) { + // We need to copy the file to where the request is supposed to have streamed it. + copy( WC_Unit_Tests_Bootstrap::instance()->tests_dir . '/data/GeoLite2-Country.tar.gz', $request['filename'] ); + + $mocked_response = array( + 'response' => array( 'code' => 200 ), + ); + } elseif ( 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=invalid_license&suffix=tar.gz' === $url ) { + return new WP_Error( 'http_404', 'Unauthorized', array( 'code' => 401 ) ); + } elseif ( 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=generic_error&suffix=tar.gz' === $url ) { + return new WP_Error( 'http_404', 'Unauthorized', array( 'code' => 500 ) ); + } elseif ( 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=archive_error&suffix=tar.gz' === $url ) { + $mocked_response = array( + 'response' => array( 'code' => 200 ), + ); + } + + return $mocked_response; + } +} diff --git a/tests/unit-tests/integrations/maxmind-geolocation/class-wc-tests-maxmind-integration.php b/tests/unit-tests/integrations/maxmind-geolocation/class-wc-tests-maxmind-integration.php new file mode 100644 index 00000000000..e7bbbd3e517 --- /dev/null +++ b/tests/unit-tests/integrations/maxmind-geolocation/class-wc-tests-maxmind-integration.php @@ -0,0 +1,125 @@ +database_service = $this->getMockBuilder( 'WC_Integration_maxMind_Database_Service' ) + ->disableOriginalConstructor() + ->getMock(); + add_filter( 'woocommerce_maxmind_geolocation_database_service', array( $this, 'override_integration_service' ) ); + } + + /** + * Make sure that the database is not updated if no target database path is given. + */ + public function test_update_database_does_nothing_without_database_path() { + $this->database_service->expects( $this->once() ) + ->method( 'get_database_path' ) + ->willReturn( '' ); + + ( new WC_Integration_MaxMind_Geolocation() )->update_database(); + } + + /** + * Makes sure that the database can be updated to a given database. + */ + public function test_update_database_to_parameter_file() { + $this->database_service->expects( $this->once() ) + ->method( 'get_database_path' ) + ->willReturn( '/testing' ); + + ( new WC_Integration_MaxMind_Geolocation() )->update_database( '/tmp/noop.mmdb' ); + } + + /** + * Makes sure that the integration uses the license key correctly. + */ + public function test_update_database_uses_license_key() { + $this->database_service->expects( $this->once() ) + ->method( 'get_database_path' ) + ->willReturn( '/testing' ); + $this->database_service->expects( $this->once() ) + ->method( 'download_database' ) + ->with( 'test_license' ) + ->willReturn( '/tmp/' . WC_Integration_MaxMind_Database_Service::DATABASE . '.' . WC_Integration_MaxMind_Database_Service::DATABASE_EXTENSION ); + + $integration = new WC_Integration_MaxMind_Geolocation(); + $integration->update_option( 'license_key', 'test_license' ); + + $integration->update_database(); + } + + /** + * Make sure that the geolocate_ip method does not squash existing country codes. + */ + public function test_geolocate_ip_returns_existing_country_code() { + $data = ( new WC_Integration_MaxMind_Geolocation() )->get_geolocation( array( 'country' => 'US' ), '192.168.1.1' ); + + $this->assertEquals( 'US', $data['country'] ); + } + + /** + * Make sure that the geolocate_ip method does nothing if IP is not set. + */ + public function test_geolocate_ip_returns_empty_without_ip_address() { + $data = ( new WC_Integration_MaxMind_Geolocation() )->get_geolocation( array(), '' ); + + $this->assertEmpty( $data ); + } + + /** + * Make sure that the geolocate_ip method uses the appropriate service methods.. + */ + public function test_geolocate_ip_uses_service() { + $this->database_service->expects( $this->once() ) + ->method( 'get_iso_country_code_for_ip' ) + ->with( '192.168.1.1' ) + ->willReturn( 'US' ); + + $data = ( new WC_Integration_MaxMind_Geolocation() )->get_geolocation( array(), '192.168.1.1' ); + + $this->assertEquals( 'US', $data['country'] ); + } + + /** + * Overrides the filesystem method. + * + * @return string + */ + public function override_filesystem_method() { + return 'Base'; + } + + /** + * Overrides the database service used by the integration. + * + * @return mixed + */ + public function override_integration_service() { + return $this->database_service; + } +} diff --git a/tests/unit-tests/log/log-handler-file.php b/tests/unit-tests/log/log-handler-file.php index c93c85dc981..60ccbf6212e 100644 --- a/tests/unit-tests/log/log-handler-file.php +++ b/tests/unit-tests/log/log-handler-file.php @@ -205,7 +205,7 @@ class WC_Tests_Log_Handler_File extends WC_Unit_Test_Case { */ public function test_get_log_file_path() { $log_dir = trailingslashit( WC_LOG_DIR ); - $date_suffix = date( 'Y-m-d', current_time( 'timestamp', true ) ); + $date_suffix = date( 'Y-m-d', time() ); $hash_name = sanitize_file_name( wp_hash( 'unit-tests' ) ); $this->assertEquals( $log_dir . 'unit-tests-' . $date_suffix . '-' . $hash_name . '.log', WC_Log_Handler_File::get_log_file_path( 'unit-tests' ) ); } diff --git a/tests/unit-tests/order/class-wc-tests-order-functions.php b/tests/unit-tests/order/class-wc-tests-order-functions.php index 48619434b57..81e94b0e73a 100644 --- a/tests/unit-tests/order/class-wc-tests-order-functions.php +++ b/tests/unit-tests/order/class-wc-tests-order-functions.php @@ -1430,4 +1430,92 @@ class WC_Tests_Order_Functions extends WC_Unit_Test_Case { // Should return nothing when searching for nonexistent term. $this->assertEmpty( wc_order_search( 'Nonexistent term' ) ); } + + /** + * Checks if hold coupons are released when increasing usage count. + * + * @throws Exception When unable to create an order. + */ + public function test_wc_update_coupon_usage_counts() { + $coupon_code = 'coupon1'; + $coupon_data_store = WC_Data_Store::load( 'coupon' ); + + $coupon = WC_Helper_Coupon::create_coupon( + $coupon_code, + array( + 'usage_limit' => 2, + 'usage_limit_per_user' => 2, + ) + ); + + $product = WC_Helper_Product::create_simple_product( true ); + WC()->cart->add_to_cart( $product->get_id(), 1 ); + WC()->cart->add_discount( $coupon_code ); + $this->assertEquals( 0, $coupon_data_store->get_usage_by_email( $coupon, 'a@b.com' ) ); + + $order_id = WC_Checkout::instance()->create_order( + array( + 'billing_email' => 'a@b.com', + 'payment_method' => 'dummy', + ) + ); + + $this->assertEquals( 0, $coupon->get_usage_count() ); + $this->assertEquals( 1, $coupon_data_store->get_tentative_usage_count( $coupon->get_id() ) ); + $this->assertEquals( 1, $coupon_data_store->get_tentative_usages_for_user( $coupon->get_id(), array( 'a@b.com' ) ) ); + $this->assertEquals( 1, $coupon_data_store->get_usage_by_email( $coupon, 'a@b.com' ) ); + + $order = new WC_Order( $order_id ); + $order->update_status( 'processing' ); + + $this->assertEquals( 1, get_post_meta( $coupon->get_id(), 'usage_count', true ) ); + $this->assertEquals( 0, $coupon_data_store->get_tentative_usage_count( $coupon->get_id() ) ); + $this->assertEquals( 1, $coupon_data_store->get_usage_by_email( $coupon, 'a@b.com' ) ); + $this->assertEquals( 0, $coupon_data_store->get_tentative_usages_for_user( $coupon->get_id(), array( 'a@b.com' ) ) ); + } + + /** + * Test if everything works as expected when coupon hold is disabled using filter. + */ + public function test_wc_update_usage_count_without_coupon_hold() { + $coupon_code = 'coupon1'; + $coupon_data_store = WC_Data_Store::load( 'coupon' ); + + $coupon = WC_Helper_Coupon::create_coupon( + $coupon_code, + array( + 'usage_limit' => 2, + 'usage_limit_per_user' => 2, + ) + ); + + $product = WC_Helper_Product::create_simple_product( true ); + WC()->cart->add_to_cart( $product->get_id(), 1 ); + WC()->cart->add_discount( $coupon_code ); + $this->assertEquals( 0, $coupon_data_store->get_usage_by_email( $coupon, 'a@b.com' ) ); + + add_filter( 'woocommerce_hold_stock_for_checkout', '__return_false' ); + + $order_id = WC_Checkout::instance()->create_order( + array( + 'billing_email' => 'a@b.com', + 'payment_method' => 'dummy', + ) + ); + + $this->assertEquals( 0, $coupon->get_usage_count() ); + $this->assertEquals( 0, $coupon_data_store->get_tentative_usage_count( $coupon->get_id() ) ); + $this->assertEquals( 0, $coupon_data_store->get_tentative_usages_for_user( $coupon->get_id(), array( 'a@b.com' ) ) ); + $this->assertEquals( 0, $coupon_data_store->get_usage_by_email( $coupon, 'a@b.com' ) ); + + $order = new WC_Order( $order_id ); + $order->update_status( 'processing' ); + + $this->assertEquals( 1, get_post_meta( $coupon->get_id(), 'usage_count', true ) ); + $this->assertEquals( 0, $coupon_data_store->get_tentative_usage_count( $coupon->get_id() ) ); + $this->assertEquals( 1, $coupon_data_store->get_usage_by_email( $coupon, 'a@b.com' ) ); + $this->assertEquals( 0, $coupon_data_store->get_tentative_usages_for_user( $coupon->get_id(), array( 'a@b.com' ) ) ); + + remove_filter( 'woocommerce_hold_stock_for_checkout', '__return_false' ); + } } diff --git a/tests/unit-tests/order/class-wc-tests-orders.php b/tests/unit-tests/order/class-wc-tests-orders.php index 72f41dff20b..34d7227143d 100644 --- a/tests/unit-tests/order/class-wc-tests-orders.php +++ b/tests/unit-tests/order/class-wc-tests-orders.php @@ -20,7 +20,7 @@ class WC_Tests_Order extends WC_Unit_Test_Case { update_option( 'woocommerce_calc_taxes', 'yes' ); update_option( 'woocommerce_tax_round_at_subtotal', 'yes' ); - $tax_rate = array( + $tax_rate = array( 'tax_rate_country' => '', 'tax_rate_state' => '', 'tax_rate' => '7.0000', diff --git a/tests/unit-tests/payment-gateways/payment-gateways.php b/tests/unit-tests/payment-gateways/payment-gateways.php new file mode 100644 index 00000000000..7f839c0badd --- /dev/null +++ b/tests/unit-tests/payment-gateways/payment-gateways.php @@ -0,0 +1,59 @@ +session = null; + $wc_payment_gateways = WC_Payment_Gateways::instance(); + $wc_payment_gateways->init(); + foreach ( $wc_payment_gateways->payment_gateways() as $name => $gateway ) { + if ( in_array( $name, array( 'cod', 'bacs' ) ) ) { + $gateway->enabled = 'yes'; + } + } + } + + /** + * Initialize session that some tests might have removed. + */ + public function tearDown() { + parent::tearDown(); + WC()->initialize_session(); + } + + /** + * Test that we can set a current gateway from session. Basic smoke test. + */ + public function test_wc_set_current_gateway_from_session() { + WC()->initialize_session(); + wp_set_current_user( 1 ); + + $gateways = WC()->payment_gateways()->get_available_payment_gateways(); + $gateways['bacs']->chosen = false; + WC()->session->set( 'chosen_payment_method', 'bacs' ); + WC()->payment_gateways()->set_current_gateway( $gateways ); + $this->assertTrue( $gateways['bacs']->chosen ); + } + + /** + * Test that we can set a current gateway without session. + */ + public function test_wc_set_current_gateway_without_session() { + $gateways = WC()->payment_gateways()->get_available_payment_gateways(); + $current_gateway = current( $gateways ); + $current_gateway->chosen = false; + WC()->payment_gateways()->set_current_gateway( $gateways ); + $this->assertTrue( $current_gateway->chosen ); + } + +} diff --git a/tests/unit-tests/product/data-store.php b/tests/unit-tests/product/data-store.php index f39ca4db78d..b67ad8a4621 100644 --- a/tests/unit-tests/product/data-store.php +++ b/tests/unit-tests/product/data-store.php @@ -797,6 +797,12 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case { $this->assertContains( $product3->get_id(), $results ); $this->assertContains( $product4->get_id(), $results ); + $results = $data_store->search_products( 'blue-widget-1 OR green-widget', '', true, true ); + $this->assertContains( $product->get_id(), $results ); + $this->assertNotContains( $product2->get_id(), $results ); + $this->assertContains( $product3->get_id(), $results ); + $this->assertContains( $product4->get_id(), $results ); + $results = $data_store->search_products( '"green widget"', '', true, true ); $this->assertNotContains( $product->get_id(), $results ); $this->assertNotContains( $product2->get_id(), $results ); diff --git a/tests/unit-tests/shipping-zones/shipping-zone.php b/tests/unit-tests/shipping/shipping-zone.php similarity index 98% rename from tests/unit-tests/shipping-zones/shipping-zone.php rename to tests/unit-tests/shipping/shipping-zone.php index d7954f9294b..99d7dac7c99 100644 --- a/tests/unit-tests/shipping-zones/shipping-zone.php +++ b/tests/unit-tests/shipping/shipping-zone.php @@ -1,12 +1,13 @@ assertTrue( is_array( $zones ) ); $this->assertTrue( 4 === count( $zones ) ); } @@ -28,10 +36,10 @@ class WC_Tests_Shipping_Zones extends WC_Unit_Test_Case { * Test: WC_Shipping_Zones::get_zone */ public function test_get_zone() { - // Test + // Test. $zone = WC_Shipping_Zones::get_zone( 1 ); - // Assert that the first zone is our local zone + // Assert that the first zone is our local zone. $this->assertInstanceOf( 'WC_Shipping_Zone', $zone ); $this->assertEquals( $zone->get_zone_name(), 'Local' ); } @@ -40,19 +48,19 @@ class WC_Tests_Shipping_Zones extends WC_Unit_Test_Case { * Test: WC_Shipping_Zones::get_zone_by */ public function test_get_zone_by() { - // Test + // Test. $zone = WC_Shipping_Zones::get_zone_by( 'zone_id', 2 ); - // Assert + // Assert. $this->assertInstanceOf( 'WC_Shipping_Zone', $zone ); $this->assertEquals( $zone->get_zone_name(), 'Europe' ); - // Test instance_id + // Test instance_id. $instance_id = $zone->add_shipping_method( 'flat_rate' ); $zone = WC_Shipping_Zones::get_zone_by( 'instance_id', $instance_id ); - // Assert + // Assert. $this->assertInstanceOf( 'WC_Shipping_Zone', $zone ); $this->assertEquals( $zone->get_zone_name(), 'Europe' ); } @@ -61,12 +69,12 @@ class WC_Tests_Shipping_Zones extends WC_Unit_Test_Case { * Test: WC_Shipping_Zones::get_shipping_method */ public function test_get_shipping_method() { - // Test + // Test. $zone = WC_Shipping_Zones::get_zone_by( 'zone_id', 1 ); $instance_id = $zone->add_shipping_method( 'flat_rate' ); $shipping_method = WC_Shipping_Zones::get_shipping_method( $instance_id ); - // Assert + // Assert. $this->assertInstanceOf( 'WC_Shipping_Flat_Rate', $shipping_method ); } @@ -74,11 +82,11 @@ class WC_Tests_Shipping_Zones extends WC_Unit_Test_Case { * Test: WC_Shipping_Zones::delete_zone */ public function test_delete_zone() { - // Test + // Test. WC_Shipping_Zones::delete_zone( 1 ); $zones = WC_Shipping_Zones::get_zones(); - // Assert + // Assert. $this->assertTrue( 3 === count( $zones ) ); } @@ -86,7 +94,7 @@ class WC_Tests_Shipping_Zones extends WC_Unit_Test_Case { * Test: WC_Shipping_Zones::get_zone_matching_package */ public function test_get_zone_matching_package() { - // Test + // Test. $zone1 = WC_Shipping_Zones::get_zone_matching_package( array( 'destination' => array( @@ -124,7 +132,7 @@ class WC_Tests_Shipping_Zones extends WC_Unit_Test_Case { ) ); - // Assert + // Assert. $this->assertEquals( 'Local', $zone1->get_zone_name() ); $this->assertEquals( 'Europe', $zone2->get_zone_name() ); $this->assertEquals( 'California', $zone3->get_zone_name() ); diff --git a/tests/unit-tests/shipping/shipping.php b/tests/unit-tests/shipping/shipping.php new file mode 100644 index 00000000000..87c2d6b7569 --- /dev/null +++ b/tests/unit-tests/shipping/shipping.php @@ -0,0 +1,76 @@ +is_package_shippable( + array( + 'destination' => array( + 'country' => '', + 'state' => 'CA', + 'postcode' => '99999', + 'address' => '', + ), + ) + ); + $this->assertFalse( $result ); + + // Failure for disallowed country. + $result = $shipping->is_package_shippable( + array( + 'destination' => array( + 'country' => 'TEST', + 'state' => 'CA', + 'postcode' => '99999', + 'address' => '', + ), + ) + ); + $this->assertFalse( $result ); + + // Failure for no state when required. + $result = $shipping->is_package_shippable( + array( + 'destination' => array( + 'country' => 'US', + 'state' => '', + 'postcode' => '99999', + 'address' => '', + ), + ) + ); + $this->assertFalse( $result ); + + // Success for correct address. + $result = $shipping->is_package_shippable( + array( + 'destination' => array( + 'country' => 'US', + 'state' => 'CA', + 'postcode' => '99999', + 'address' => '', + ), + ) + ); + $this->assertTrue( $result ); + } +} diff --git a/tests/unit-tests/totals/totals.php b/tests/unit-tests/totals/totals.php index ec4ab27966b..2edd6d00fd2 100644 --- a/tests/unit-tests/totals/totals.php +++ b/tests/unit-tests/totals/totals.php @@ -30,6 +30,13 @@ class WC_Tests_Totals extends WC_Unit_Test_Case { public function setUp() { parent::setUp(); + // Set a valid address for the customer so shipping rates will calculate. + WC()->customer->set_shipping_country( 'US' ); + WC()->customer->set_shipping_state( 'NY' ); + WC()->customer->set_shipping_postcode( '12345' ); + + WC()->cart->empty_cart(); + $this->ids = array(); $tax_rate = array( diff --git a/tests/unit-tests/util/api-functions.php b/tests/unit-tests/util/api-functions.php index 9379a4d2198..bdd1ebf7653 100644 --- a/tests/unit-tests/util/api-functions.php +++ b/tests/unit-tests/util/api-functions.php @@ -82,8 +82,12 @@ class WC_Tests_API_Functions extends WC_Unit_Test_Case { */ public function test_wc_rest_upload_image_from_url_should_return_error_when_invalid_image_is_passed() { // empty file. - $expected_error_message = 'Invalid image: File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.'; - $result = wc_rest_upload_image_from_url( 'http://somedomain.com/invalid-image-1.png' ); + if ( version_compare( get_bloginfo( 'version' ), '5.4-alpha', '>=' ) ) { + $expected_error_message = 'Invalid image: File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini file or by post_max_size being defined as smaller than upload_max_filesize in php.ini.'; + } else { + $expected_error_message = 'Invalid image: File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.'; + } + $result = wc_rest_upload_image_from_url( 'http://somedomain.com/invalid-image-1.png' ); $this->assertWPError( $result ); $this->assertEquals( $expected_error_message, $result->get_error_message() ); diff --git a/tests/unit-tests/util/class-wc-rate-limiter.php b/tests/unit-tests/util/class-wc-rate-limiter.php index e630e9873d9..7ec2562d042 100644 --- a/tests/unit-tests/util/class-wc-rate-limiter.php +++ b/tests/unit-tests/util/class-wc-rate-limiter.php @@ -31,8 +31,8 @@ class WC_Tests_Rate_Limiter extends WC_Unit_Test_Case { */ public function test_rate_limit_limits() { $action_identifier = 'action_1'; - $user_1_id = 10; - $user_2_id = 15; + $user_1_id = 10; + $user_2_id = 15; $rate_limit_id_1 = $action_identifier . $user_1_id; $rate_limit_id_2 = $action_identifier . $user_2_id; diff --git a/tests/unit-tests/util/class-wc-tests-core-functions.php b/tests/unit-tests/util/class-wc-tests-core-functions.php index a2337b5bae6..4ae30ddb806 100644 --- a/tests/unit-tests/util/class-wc-tests-core-functions.php +++ b/tests/unit-tests/util/class-wc-tests-core-functions.php @@ -281,7 +281,7 @@ class WC_Tests_Core_Functions extends WC_Unit_Test_Case { public function test_wc_get_log_file_path() { $log_dir = trailingslashit( WC_LOG_DIR ); $hash_name = sanitize_file_name( wp_hash( 'unit-tests' ) ); - $date_suffix = date( 'Y-m-d', current_time( 'timestamp', true ) ); + $date_suffix = date( 'Y-m-d', time() ); $this->assertEquals( $log_dir . 'unit-tests-' . $date_suffix . '-' . $hash_name . '.log', wc_get_log_file_path( 'unit-tests' ) ); } diff --git a/woocommerce.php b/woocommerce.php index 24f705f1ebb..c6c9676aaa1 100644 --- a/woocommerce.php +++ b/woocommerce.php @@ -3,7 +3,7 @@ * Plugin Name: WooCommerce * Plugin URI: https://woocommerce.com/ * Description: An eCommerce toolkit that helps you sell anything. Beautifully. - * Version: 3.9.0-beta.2 + * Version: 3.9.0 * Author: Automattic * Author URI: https://woocommerce.com * Text Domain: woocommerce