diff --git a/tests/ActivationTest.php b/tests/ActivationTest.php
new file mode 100644
index 0000000..19b3bf4
--- /dev/null
+++ b/tests/ActivationTest.php
@@ -0,0 +1,64 @@
+ 7,
+ 'data' => (object) array('user_email' => 'admin@shop.test'),
+ );
+ $GLOBALS['spiff_test_user_meta'][7] = array(
+ 'billing_phone' => '0400 000 000',
+ 'first_name' => 'Jamie',
+ 'last_name' => 'Smith',
+ );
+ }
+
+ public function testFirstActivationNotifiesSpiff() {
+ $this->addAdmin();
+
+ spiff_activation_hook();
+
+ $this->assertCount(1, $GLOBALS['spiff_test_requests']);
+ $request = $GLOBALS['spiff_test_requests'][0];
+ $this->assertSame(SPIFF_TEST_AP_BASE . '/graphql', $request['url']);
+ $body = json_decode($request['args']['body'], true);
+ $this->assertSame('InstallNotify', $body['operationName']);
+ $this->assertSame(array(
+ 'type' => 'WooCommerce',
+ 'shopName' => 'https://shop.test',
+ 'owner' => 'Jamie Smith',
+ 'email' => 'admin@shop.test',
+ 'phone' => '0400 000 000',
+ ), $body['variables']['input']);
+ }
+
+ public function testFirstActivationIsRecorded() {
+ $this->addAdmin();
+
+ spiff_activation_hook();
+
+ $this->assertSame('1', get_option('spiff_plugin_was_activated'));
+ }
+
+ public function testLaterActivationsDoNotNotifySpiff() {
+ $this->addAdmin();
+ $GLOBALS['spiff_test_options']['spiff_plugin_was_activated'] = '1';
+
+ spiff_activation_hook();
+
+ $this->assertCount(0, $GLOBALS['spiff_test_requests']);
+ }
+
+ public function testActivationWithoutAdminsDoesNotNotifySpiff() {
+ spiff_activation_hook();
+
+ $this->assertCount(0, $GLOBALS['spiff_test_requests']);
+ $this->assertSame('1', get_option('spiff_plugin_was_activated'));
+ }
+}
diff --git a/tests/AdminTest.php b/tests/AdminTest.php
new file mode 100644
index 0000000..7b95aef
--- /dev/null
+++ b/tests/AdminTest.php
@@ -0,0 +1,81 @@
+assertSame(array(array(
+ 'page_title' => 'Spiff Connect',
+ 'menu_title' => 'Spiff Connect',
+ 'capability' => 'administrator',
+ 'menu_slug' => 'spiff-connect',
+ 'callback' => 'spiff_admin_menu_html',
+ )), $GLOBALS['spiff_test_menu_pages']);
+ $this->assertTrue(spiff_test_has_action('admin_init', 'spiff_register_admin_settings'));
+ }
+
+ public function testRegistersSettings() {
+ spiff_register_admin_settings();
+
+ $this->assertSame(array(
+ 'spiff_application_key',
+ 'spiff_infrastructure',
+ 'spiff_show_customer_selections_in_cart',
+ 'spiff_show_preview_images_in_cart',
+ 'spiff_non_bulk_text',
+ 'spiff_font_size',
+ 'spiff_font_weight',
+ 'spiff_text_color',
+ 'spiff_background_color',
+ 'spiff_width',
+ 'spiff_height',
+ 'spiff_customer_portal_button_text',
+ 'spiff_customer_portal_button_font_size',
+ 'spiff_customer_portal_button_font_weight',
+ 'spiff_customer_portal_button_text_color',
+ 'spiff_customer_portal_button_background_color',
+ 'spiff_customer_portal_button_width',
+ 'spiff_customer_portal_button_height',
+ ), $GLOBALS['spiff_test_settings']['spiff-settings-group']);
+ }
+
+ public function testAddsProductFields() {
+ spiff_create_admin_product_fields();
+
+ $fields = $GLOBALS['spiff_test_product_fields'];
+ $this->assertCount(2, $fields);
+ $this->assertSame('checkbox', $fields[0]['type']);
+ $this->assertSame('spiff_enabled', $fields[0]['id']);
+ $this->assertSame('text', $fields[1]['type']);
+ $this->assertSame('spiff_integration_product_id', $fields[1]['id']);
+ }
+
+ public function testSavesEnabledProductFields() {
+ $product = new Spiff_Test_Product(42);
+ $GLOBALS['spiff_test_products'][42] = $product;
+ $_POST = array('spiff_enabled' => 'yes', 'spiff_integration_product_id' => ' integration-product-1 ');
+
+ spiff_save_admin_product_fields(42);
+
+ $this->assertSame('yes', $product->meta['spiff_enabled']);
+ $this->assertSame('integration-product-1', $product->meta['spiff_integration_product_id']);
+ $this->assertTrue($product->saved);
+ }
+
+ public function testSavesDisabledProductFieldsWhenCheckboxIsUnticked() {
+ $product = new Spiff_Test_Product(42, array('spiff_enabled' => 'yes'));
+ $GLOBALS['spiff_test_products'][42] = $product;
+ $_POST = array('spiff_integration_product_id' => 'integration-product-1');
+
+ spiff_save_admin_product_fields(42);
+
+ $this->assertSame('no', $product->meta['spiff_enabled']);
+ $this->assertTrue($product->saved);
+ }
+}
diff --git a/tests/CartTest.php b/tests/CartTest.php
new file mode 100644
index 0000000..b9e862d
--- /dev/null
+++ b/tests/CartTest.php
@@ -0,0 +1,191 @@
+ array('transactions' => array(array(
+ 'priceModifierTotal' => 250,
+ 'product' => array(
+ 'basePrice' => 1000,
+ 'integrationProducts' => array(array('id' => 'integration-product-1')),
+ ),
+ )))));
+ }
+
+ private function postCartItemDetails($details) {
+ // WordPress adds slashes to request data, which the plugin strips.
+ $_POST['spiff_create_cart_item_details'] = addslashes(json_encode($details));
+ }
+
+ // Adding designs to the cart.
+
+ public function testAddsDesignToCart() {
+ $this->queueTransaction();
+ $this->postCartItemDetails(array(
+ 'transactionId' => 'transaction-1',
+ 'wooProductId' => '42',
+ 'exportedData' => array('Name' => array('value' => 'Jamie')),
+ ));
+
+ spiff_create_cart_item();
+
+ $this->assertSame(array(array(
+ 'product_id' => '42',
+ 'quantity' => 1,
+ 'variation_id' => '',
+ 'variation' => '',
+ 'cart_item_data' => array(
+ 'spiff_exported_data' => array('Name' => 'Jamie'),
+ 'spiff_transaction_id' => 'transaction-1',
+ 'spiff_item_price' => 12.5,
+ ),
+ )), $GLOBALS['woocommerce']->cart->added);
+ $this->assertSame(1, $GLOBALS['spiff_test_wp_die_calls']);
+ }
+
+ public function testRequestsTransactionFromSpiff() {
+ $this->queueTransaction();
+ $this->postCartItemDetails(array(
+ 'transactionId' => 'transaction-1',
+ 'wooProductId' => '42',
+ 'exportedData' => array(),
+ ));
+
+ spiff_create_cart_item();
+
+ $request = $GLOBALS['spiff_test_requests'][0];
+ $this->assertSame(SPIFF_TEST_AP_BASE . '/graphql', $request['url']);
+ $this->assertSame('test-application-key', $request['args']['headers']['X-Application-Key']);
+ $this->assertStringContainsString('transaction-1', json_decode($request['args']['body'], true)['query']);
+ }
+
+ public function testFindsProductFromIntegrationProductWhenProductIdIsMissing() {
+ $GLOBALS['spiff_test_products'] = array(
+ 41 => new Spiff_Test_Product(41, array('spiff_integration_product_id' => 'integration-product-other')),
+ 42 => new Spiff_Test_Product(42, array('spiff_integration_product_id' => 'integration-product-1')),
+ );
+ $this->queueTransaction();
+ $this->postCartItemDetails(array(
+ 'transactionId' => 'transaction-1',
+ 'exportedData' => array(),
+ ));
+
+ spiff_create_cart_item();
+
+ $this->assertSame('42', $GLOBALS['woocommerce']->cart->added[0]['product_id']);
+ }
+
+ public function testSanitisesCustomerSelections() {
+ $this->queueTransaction();
+ $this->postCartItemDetails(array(
+ 'transactionId' => 'transaction-1',
+ 'wooProductId' => '42',
+ 'exportedData' => array('Name' => array('value' => ' Jamie ')),
+ ));
+
+ spiff_create_cart_item();
+
+ $this->assertSame(
+ array('Name' => 'Jamie'),
+ $GLOBALS['woocommerce']->cart->added[0]['cart_item_data']['spiff_exported_data']
+ );
+ }
+
+ public function testDoesNothingWithoutCartItemDetails() {
+ spiff_create_cart_item();
+
+ $this->assertCount(0, $GLOBALS['spiff_test_requests']);
+ $this->assertCount(0, $GLOBALS['woocommerce']->cart->added);
+ $this->assertSame(1, $GLOBALS['spiff_test_wp_die_calls']);
+ }
+
+ // Cart prices.
+
+ public function testSetsPriceOfSpiffItems() {
+ $spiff_product = new Spiff_Test_Product(42);
+ $other_product = new Spiff_Test_Product(43);
+ $GLOBALS['woocommerce']->cart->items = array(
+ array('data' => $spiff_product, 'spiff_item_price' => 12.5),
+ array('data' => $other_product),
+ );
+
+ spiff_handle_cart_item_price($GLOBALS['woocommerce']->cart);
+
+ $this->assertSame(12.5, $spiff_product->price);
+ $this->assertNull($other_product->price);
+ }
+
+ // Customer selections in cart.
+
+ public function testShowsCustomerSelectionsInCart() {
+ $cart_data = array(array('name' => 'Colour', 'value' => 'Red'));
+ $cart_item = array('spiff_exported_data' => array('Name' => 'Jamie', 'Message' => 'Hi'));
+
+ $this->assertSame(array(
+ array('name' => 'Colour', 'value' => 'Red'),
+ array('name' => 'Name', 'value' => 'Jamie'),
+ array('name' => 'Message', 'value' => '<b>Hi</b>'),
+ ), spiff_show_metadata_in_cart($cart_data, $cart_item));
+ }
+
+ // Preview images in cart.
+
+ public function testShowsPreviewImageForSpiffItems() {
+ spiff_test_queue_response(array('data' => array('transactions' => array(array(
+ 'previewImageLink' => 'https://images.spiff.test/preview.png',
+ )))));
+
+ $image = spiff_show_preview_image_in_cart('
', array('spiff_transaction_id' => 'transaction-1'), 'key');
+
+ $this->assertSame('
', $image);
+ $body = json_decode($GLOBALS['spiff_test_requests'][0]['args']['body'], true);
+ $this->assertSame(array('ids' => array('transaction-1')), $body['variables']);
+ }
+
+ public function testKeepsProductImageWhenSpiffHasNoPreview() {
+ spiff_test_queue_response(array('data' => array('transactions' => array(array('previewImageLink' => null)))));
+
+ $image = spiff_show_preview_image_in_cart('
', array('spiff_transaction_id' => 'transaction-1'), 'key');
+
+ $this->assertSame('
', $image);
+ }
+
+ public function testKeepsProductImageWhenSpiffRequestFails() {
+ spiff_test_queue_response(array('errors' => array(array('message' => 'Unauthorised'))), 401);
+
+ $image = spiff_show_preview_image_in_cart('
', array('spiff_transaction_id' => 'transaction-1'), 'key');
+
+ $this->assertSame('
', $image);
+ }
+
+ public function testKeepsProductImageForOtherItems() {
+ $image = spiff_show_preview_image_in_cart('
', array(), 'key');
+
+ $this->assertSame('
', $image);
+ $this->assertCount(0, $GLOBALS['spiff_test_requests']);
+ }
+
+ // Checkout.
+
+ public function testCopiesTransactionIdToOrderItem() {
+ $order_item = new Spiff_Test_Order_Item(array(), 1);
+
+ spiff_add_cart_item_attributes_to_order_item($order_item, 'key', array('spiff_transaction_id' => 'transaction-1'), null);
+
+ $this->assertSame('transaction-1', $order_item->get_meta('spiff_transaction_id'));
+ }
+
+ public function testLeavesOtherOrderItemsAlone() {
+ $order_item = new Spiff_Test_Order_Item(array(), 1);
+
+ spiff_add_cart_item_attributes_to_order_item($order_item, 'key', array(), null);
+
+ $this->assertSame(array(), $order_item->meta);
+ }
+}
diff --git a/tests/CreateOrderTest.php b/tests/CreateOrderTest.php
index e143da2..ab69c9d 100644
--- a/tests/CreateOrderTest.php
+++ b/tests/CreateOrderTest.php
@@ -96,6 +96,71 @@ public function testNoRequestIsSentWithoutSpiffItems() {
$this->assertCount(0, $GLOBALS['spiff_test_requests']);
}
+ public function testSendsCustomerDetailsInExternalData() {
+ $GLOBALS['spiff_test_orders'][123] = new Spiff_Test_Order(123, 'VEG-1042', array($this->spiffItem('transaction-1')), true, array(
+ 'billing_email' => 'jamie@example.test',
+ 'billing_phone' => '0400 000 000',
+ 'customer_note' => 'Leave at the door',
+ 'coupon_codes' => array('SAVE10'),
+ 'billing_first_name' => 'Jamie',
+ 'billing_city' => 'Melbourne',
+ 'shipping_address_1' => '1 Example St',
+ 'shipping_state' => 'VIC',
+ 'shipping_postcode' => '3000',
+ 'shipping_country' => 'AU',
+ ));
+
+ spiff_create_order(123);
+
+ $external_data = $this->sentVariables()['externalData'];
+ $this->assertSame('jamie@example.test', $external_data['customerEmail']);
+ $this->assertSame('0400 000 000', $external_data['customerPhone']);
+ $this->assertSame('Leave at the door', $external_data['note']);
+ $this->assertSame(array('SAVE10'), $external_data['discountCodes']);
+ $this->assertSame('Jamie', $external_data['billingAddress']['firstName']);
+ $this->assertSame('Melbourne', $external_data['billingAddress']['city']);
+ $this->assertSame('1 Example St', $external_data['shippingAddress']['address1']);
+ $this->assertSame('VIC', $external_data['shippingAddress']['province']);
+ $this->assertSame('VIC', $external_data['shippingAddress']['provinceCode']);
+ $this->assertSame('3000', $external_data['shippingAddress']['zip']);
+ $this->assertSame('AU', $external_data['shippingAddress']['country']);
+ $this->assertSame('AU', $external_data['shippingAddress']['countryCode']);
+ }
+
+ public function testSendsOrderCreateMutationToAustraliaByDefault() {
+ $this->addOrder(123, 'VEG-1042', array($this->spiffItem('transaction-1')));
+
+ spiff_create_order(123);
+
+ $request = $GLOBALS['spiff_test_requests'][0];
+ $this->assertSame(SPIFF_TEST_AP_BASE . '/graphql', $request['url']);
+ $this->assertSame('OrderCreate', json_decode($request['args']['body'], true)['operationName']);
+ }
+
+ public function testSendsOrderToUnitedStatesWhenConfigured() {
+ $GLOBALS['spiff_test_options']['spiff_infrastructure'] = 'US';
+ $this->addOrder(123, 'VEG-1042', array($this->spiffItem('transaction-1')));
+
+ spiff_create_order(123);
+
+ $this->assertSame(SPIFF_TEST_US_BASE . '/graphql', $GLOBALS['spiff_test_requests'][0]['url']);
+ }
+
+ public function testFailedRequestDoesNotStopCheckout() {
+ spiff_test_queue_response(array('errors' => array(array('message' => 'Unauthorised'))), 401);
+ $this->addOrder(123, 'VEG-1042', array($this->spiffItem('transaction-1')));
+ $log = ini_get('error_log');
+ ini_set('error_log', '/dev/null');
+
+ try {
+ spiff_create_order(123);
+ } finally {
+ ini_set('error_log', $log);
+ }
+
+ $this->assertCount(1, $GLOBALS['spiff_test_requests']);
+ }
+
public function testSendsPaidFlagAndApplicationKey() {
$this->addOrder(123, 'VEG-1042', array($this->spiffItem('transaction-1')), false);
diff --git a/tests/ProductPageTest.php b/tests/ProductPageTest.php
new file mode 100644
index 0000000..06dfec8
--- /dev/null
+++ b/tests/ProductPageTest.php
@@ -0,0 +1,149 @@
+Add to cart';
+
+ protected function setUp(): void {
+ spiff_test_reset();
+ $GLOBALS['spiff_test_options']['spiff_application_key'] = 'test-application-key';
+ }
+
+ private function enabledProduct() {
+ return new Spiff_Test_Product(42, array(
+ 'spiff_enabled' => 'yes',
+ 'spiff_integration_product_id' => 'integration-product-1',
+ ));
+ }
+
+ private function renderCreateDesignButton() {
+ ob_start();
+ spiff_append_create_design_button_on_product_page();
+ return ob_get_clean();
+ }
+
+ // Product list.
+
+ public function testLeavesListButtonAloneWhenSpiffIsDisabled() {
+ $product = new Spiff_Test_Product(42, array('spiff_enabled' => 'no'));
+
+ $this->assertSame(self::ADD_TO_CART_BUTTON, spiff_replace_default_button_on_product_list(self::ADD_TO_CART_BUTTON, $product));
+ }
+
+ public function testReplacesListButtonWithLinkToProductWhenSpiffIsEnabled() {
+ $button = spiff_replace_default_button_on_product_list(self::ADD_TO_CART_BUTTON, $this->enabledProduct());
+
+ $xml = simplexml_load_string($button);
+ $this->assertSame('https://shop.test/product/42/', (string) $xml['href']);
+ $this->assertSame('View details', (string) $xml['aria-label']);
+ $this->assertSame('View details', (string) $xml);
+ $this->assertStringNotContainsString('ajax_add_to_cart', (string) $xml['class']);
+ $this->assertStringContainsString('add_to_cart_button', (string) $xml['class']);
+ }
+
+ // Single product page.
+
+ public function testSwapsAddToCartForSpiffButtonWhenSpiffIsEnabled() {
+ add_action('woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30);
+ $GLOBALS['product'] = $this->enabledProduct();
+
+ spiff_replace_default_element_on_product_page();
+
+ $this->assertFalse(spiff_test_has_action('woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30));
+ $this->assertTrue(spiff_test_has_action('woocommerce_single_product_summary', 'spiff_append_create_design_button_on_product_page', 35));
+ }
+
+ public function testKeepsAddToCartWhenSpiffIsDisabled() {
+ add_action('woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30);
+ $GLOBALS['product'] = new Spiff_Test_Product(42, array('spiff_enabled' => 'no'));
+
+ spiff_replace_default_element_on_product_page();
+
+ $this->assertTrue(spiff_test_has_action('woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30));
+ $this->assertFalse(spiff_test_has_action('woocommerce_single_product_summary', 'spiff_append_create_design_button_on_product_page', 35));
+ }
+
+ public function testRendersCreateDesignButton() {
+ $GLOBALS['product'] = $this->enabledProduct();
+
+ $html = $this->renderCreateDesignButton();
+
+ $this->assertStringContainsString('