diff --git a/Makefile b/Makefile index 6e0868ef..c3d61c37 100644 --- a/Makefile +++ b/Makefile @@ -6,4 +6,4 @@ test: php ./bin/phpunit -c build/ phantomjs: - ./node_modules/.bin/phantomjs --webdriver=4444 --ssl-protocol=TLSv1 --ignore-ssl-errors=yes & + phantomjs --webdriver=8643 --ignore-ssl-errors=yes & diff --git a/behat.yml b/behat.yml new file mode 100644 index 00000000..6c86f17d --- /dev/null +++ b/behat.yml @@ -0,0 +1,32 @@ +# behat.yml + +default: + context: + parameters: + user: + password: + base_url: + driver: 'selenium2' + paths: + features: tests/integrations + bootstrap: %behat.paths.features%/bootstrap + extensions: + Behat\MinkExtension\Extension: + goutte: ~ + selenium2: ~ + +phantomjs: + context: + parameters: + user: + password: + base_url: + driver: 'phantomjs' + paths: + features: tests/integrations + bootstrap: %behat.paths.features%/bootstrap + extensions: + Behat\MinkExtension\Extension: + goutte: ~ + selenium2: + wd_host: "http://localhost:8643/wd/hub" diff --git a/composer.json b/composer.json index 05e58cd9..014f2b49 100644 --- a/composer.json +++ b/composer.json @@ -38,8 +38,12 @@ "symfony/dependency-injection": "~2.3" }, "require-dev": { - "behat/mink": "1.6.*@stable", - "behat/mink-selenium2-driver": "~1.1", + "behat/behat": "2.5.*@stable", + "behat/mink": "1.6.*-dev", + "behat/mink-extension": "1.3.*-dev", + "behat/mink-selenium2-driver": "1.2.*-dev", + "fabpot/goutte": "~1.0.4", + "behat/mink-goutte-driver": "1.*", "phpmd/phpmd": "~2.1.3", "phpunit/phpunit": "~4.3.1", "fzaninotto/faker": "~1.4.0", diff --git a/docs/testing.rst b/docs/testing.rst index 62d860f5..fec067b9 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -91,3 +91,57 @@ please try to use phpmd. You can see the rules in ``build/rulesets/phpmd.xml``. .. code-block:: bash php bin/phpmd src/ text build/rulesets/phpmd.xml + +Mink/Behat +================= + +This will run tests verifying that the client is able to perform it's core functionality. + +To run mink/behat integration tests, use the command: + +.. code-block:: bash + + source ./integration_tests.sh + +URL, email, and password can be passed in as arguments to integration_tests.sh like so: + +.. code-block:: + + source ./integration_tests.sh 'https://bobert.bp:8090' bobert@gmail.com 'abc123%^&@ac' + +You can configure which instance of bitpay.com this will test with to by changing the url +in the behat.yml file. Make sure you replace username and password with the credentials +used to log into the bitpay site you are testing with. + +You can also run specific tests from a command like so: + +.. code-block:: bash + + php bin/behat tests/integrations/invoice_create.feature + +And you can run specific lines from these tests by: + +.. code-block:: bash + + php bin/behat tests/integrations/invoice_create.feature:20 + +.. note:: + + Tests run individually require you to set environment variables for your bitpay + credentials or they must be set in the behat.yml file. + + Also keep in mind that rate limiters may hinder some tests and they need to be + reset every so often. + +.. note:: + + pairing.feature's test "the client has a bad port configuration to an incorrect port" + requires ports that vary from computer to computer so you may need to manually change + these in order to avoid error. + + A timing issue will occasionally occur saying: + "Notice: Undefined variable: response in + tests/integrations/bootstrap/FeatureContext.php line 368" + and there will be a message from BitPay saying: + "This endpoint does not support the `public` facade" + This is likely a timing issue and the tests will likely pass when run again. \ No newline at end of file diff --git a/env.dist b/env.dist deleted file mode 100644 index 146abb97..00000000 --- a/env.dist +++ /dev/null @@ -1,17 +0,0 @@ -#### -# -# This file is for integration testing. You MUST have these environment variables -# set or all integration tests will be skipped. -# -# To setup, you will need to export this variables like so: -# -# export BITPAY_EMAIL='josh@bitpay.com' -# export BITPAY_PASSWORD='FluffyKitty420' -# -# NOTE: Running this on the command line has the potential for them to show up -# in your history. Please make sure you do this one a secure system. -# -#### - -BITPAY_EMAIL='' -BITPAY_PASSWORD='' diff --git a/integration_tests.sh b/integration_tests.sh new file mode 100755 index 00000000..4762d4c3 --- /dev/null +++ b/integration_tests.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +set_variables () +{ + while true + do + read -p "Input Email: " EMAIL + regex="^[a-z0-9!#\$%&'*+/=?^_\`{|}~-]+(\.[a-z0-9!#$%&'*+/=?^_\`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]*[a-z0-9])?\$"; + if [[ "$EMAIL" =~ $regex ]] + then + export BITPAY_EMAIL=$EMAIL + break + else + echo "Please input a valid email" + fi + done + while true + do + read -p "Input Password: " PASSWORD + read -p "Password Confirmation: " PASSWORD2 + if [ "$PASSWORD" = "$PASSWORD2" ] + then + break + else + echo "Please input a valid password" + fi + done + while true + do + read -p "Input URL: " URL + if [ -z $URL ] + then + echo "Please input a valid URL" + else + break + fi + done +} + +if [ -z "$1" ] +then + echo "No parameters passed so using Environment Variables" + if [ -z "$BITPAY_EMAIL" ] || [ -z "$BITPAY_PASSWORD"] + then + echo "ERROR: No Email or password are set." + echo "set BITPAY_EMAIL and BITPAY_PASSWORD as environment variables" + echo "or pass them as arguments when running this script" + while true; do + read -p "Do you wish to set your environment variables here? " yn + case $yn in + [Yy]* ) set_variables; break;; + [Nn]* ) echo "Closing script"; exit;; + * ) echo "Please answer yes or no.";; + esac + done + else + echo "Environment Variables already exist for BITPAY." + fi +else + echo "Username $1 and Password $2 passed from command line" + URL=$1 + EMAIL=$2 + PASSWORD=$3 + echo "Setting user and Password to new environment variables..." + +fi + +export BITPAY_EMAIL=$EMAIL +export BITPAY_PASSWORD=$PASSWORD +export BITPAY_URL=$URL +echo "Using Email: $EMAIL" +echo "Using URL: $URL" + +echo "Removing old keys..." +if [ -e /tmp/bitpay.pub ] +then + rm -rf /tmp/bitpay.pub + rm -rf /tmp/bitpay.pri + rm -rf /tmp/token.json +fi + +echo "Checking if Selenium exists..." +if [ ! -f selenium-server-standalone-2.44.0.jar ] +then + echo "Downloading Selenium" + curl -O http://selenium-release.storage.googleapis.com/2.44/selenium-server-standalone-2.44.0.jar +fi + +echo "Running Selenium and the tests" +php bin/behat tests/integrations \ No newline at end of file diff --git a/src/Bitpay/Client/Adapter/CurlAdapter.php b/src/Bitpay/Client/Adapter/CurlAdapter.php index 833a7254..8d6327c2 100644 --- a/src/Bitpay/Client/Adapter/CurlAdapter.php +++ b/src/Bitpay/Client/Adapter/CurlAdapter.php @@ -74,7 +74,7 @@ public function sendRequest(RequestInterface $request) if (false === $raw) { $errorMessage = curl_error($curl); curl_close($curl); - throw new \Exception($errorMessage); + throw new \Bitpay\Client\ConnectionException($errorMessage); } /** @var ResponseInterface */ diff --git a/src/Bitpay/Client/ArgumentException.php b/src/Bitpay/Client/ArgumentException.php new file mode 100644 index 00000000..3f1aa746 --- /dev/null +++ b/src/Bitpay/Client/ArgumentException.php @@ -0,0 +1,8 @@ +request = $this->createNewRequest(); $this->request->setMethod(Request::METHOD_POST); $this->request->setPath('tokens'); @@ -478,7 +484,7 @@ public function createToken(array $payload = array()) $body = json_decode($this->response->getBody(), true); if (isset($body['error'])) { - throw new \Exception($body['error']); + throw new \Bitpay\Client\BitpayException($this->response->getStatusCode().": ".$body['error']); } $tkn = $body['data'][0]; @@ -590,7 +596,7 @@ protected function addSignatureHeader(RequestInterface $request) throw new \Exception('Please set your Private Key'); } - if (isset($this->network->isPortRequiredInUrl)) { + if (true == property_exists($this->network, 'isPortRequiredInUrl')) { if ($this->network->isPortRequiredInUrl === true) { $url = $request->getUriWithPort(); } diff --git a/src/Bitpay/Client/ConnectionException.php b/src/Bitpay/Client/ConnectionException.php new file mode 100644 index 00000000..ca4fc580 --- /dev/null +++ b/src/Bitpay/Client/ConnectionException.php @@ -0,0 +1,8 @@ +price = $price; return $this; diff --git a/tests/Bitpay/Client/Adapter/CurlAdapterTest.php b/tests/Bitpay/Client/Adapter/CurlAdapterTest.php index 0e769403..b511ab31 100644 --- a/tests/Bitpay/Client/Adapter/CurlAdapterTest.php +++ b/tests/Bitpay/Client/Adapter/CurlAdapterTest.php @@ -31,8 +31,7 @@ public function testGetCurlOptions() public function testSendRequestWithException() { - $http = $this->getMock('HttpRequest'); - $this->setExpectedException('Exception'); + $this->setExpectedException('Bitpay\Client\ConnectionException'); $curl_options = array( CURLOPT_URL => "www.example.com", @@ -46,8 +45,6 @@ public function testSendRequestWithException() public function testSendRequestWithoutException() { - $http = $this->getMock('HttpRequest'); - $curl_options = array( CURLOPT_URL => "www.bitpay.com", CURLOPT_SSL_VERIFYPEER => 1, diff --git a/tests/integrations/CreatePairingCodeTest.php b/tests/integrations/CreatePairingCodeTest.php deleted file mode 100644 index 37af29b1..00000000 --- a/tests/integrations/CreatePairingCodeTest.php +++ /dev/null @@ -1,131 +0,0 @@ -markTestSkipped('Environment Variables need to be set.'); - return; - } - - $selenium2driver = new Selenium2Driver('firefox', null, 'http://127.0.0.1:4444'); - $this->mink = new Mink( - array( - 'selenium2' => new Session($selenium2driver), - ) - ); - $this->mink->setDefaultSessionName('selenium2'); - } - - protected function tearDown() - { - $this->mink->getSession()->reset(); - } - - public function testPairingCode() - { - /** - * Login and create a pairing code - */ - $this->login(); - $pairingCode = $this->createPairingCode(); - - /** - * Generate some new keys - */ - list($pri, $pub, $sin) = $this->generateKeys(); - - /** - * Make request to to pair keys and obtain a token - */ - $this->client = new \Bitpay\Client\Client(); - $this->client->setNetwork(new \Bitpay\Network\Testnet()); - $this->client->setPublicKey($pub); - $this->client->setPrivateKey($pri); - $this->client->setAdapter(new \Bitpay\Client\Adapter\CurlAdapter()); - $token = $this->client->createToken( - array( - 'id' => (string) $sin, - 'pairingCode' => $pairingCode, - 'label' => 'Integration Test', - ) - ); - /** - * The token is the what will be needed for all requests in the future - * and so to inject it into the client, you would add the code - * - * $client->setToken($token); - * - */ - $this->assertInstanceOf('Bitpay\TokenInterface', $token); - } - - private function login() - { - $this->mink->getSession()->visit('https://test.bitpay.com/merchant-login'); - $this->mink->getSession()->wait(2500); - $this->mink->getSession()->getPage()->fillField('email', getenv('BITPAY_EMAIL')); - $this->mink->getSession()->getPage()->fillField('password', getenv('BITPAY_PASSWORD')); - $this->mink->getSession()->getPage()->findById('loginForm')->submit(); - $this->mink->getSession()->wait(2500); - $assert = $this->mink->assertSession(); - $assert->pageTextContains('Dashboard'); - } - - private function createPairingCode() - { - $this->mink->getSession()->visit('https://test.bitpay.com/api-tokens'); - $session = $this->mink->getSession(); - $page = $session->getPage(); - // Click the `Add New Token` button - $page->find('xpath', '//*[@id="apiTokensList"]/div/div[3]/div[2]/div')->click(); - $this->mink->getSession()->wait(500); - $assert = $this->mink->assertSession(); - $assert->pageTextContains('Add Token'); - // Click `Add Token` button - $page->find('xpath', '//*[@id="token-new-form"]/button')->click(); - $this->mink->getSession()->wait(2500); - $pairingCode = $page->find('xpath', '//*[@id="my-token-access-wrapper"]/div[1]/div[2]/div/div')->getText(); - $this->assertNotNull($pairingCode); - - return $pairingCode; - } - - private function generateKeys() - { - $privateKey = new \Bitpay\PrivateKey(); - $privateKey->generate(); - $publicKey = new \Bitpay\PublicKey(); - $publicKey - ->setPrivateKey($privateKey) - ->generate(); - $sin = new \Bitpay\SinKey(); - $sin - ->setPublicKey($publicKey) - ->generate(); - - return array( - $privateKey, - $publicKey, - $sin, - ); - } -} diff --git a/tests/integrations/LoginTest.php b/tests/integrations/LoginTest.php deleted file mode 100644 index 81a56872..00000000 --- a/tests/integrations/LoginTest.php +++ /dev/null @@ -1,53 +0,0 @@ -markTestSkipped('Environment Variables need to be set.'); - return; - } - - $selenium2driver = new Selenium2Driver('firefox', null, 'http://127.0.0.1:4444'); - $this->mink = new Mink( - array( - 'selenium2' => new Session($selenium2driver), - ) - ); - $this->mink->setDefaultSessionName('selenium2'); - } - - protected function tearDown() - { - $this->mink->getSession()->reset(); - } - - public function testLogin() - { - $this->mink->getSession()->visit('https://test.bitpay.com/merchant-login'); - $this->mink->getSession()->getPage()->fillField('email', getenv('BITPAY_EMAIL')); - $this->mink->getSession()->getPage()->fillField('password', getenv('BITPAY_PASSWORD')); - $this->mink->getSession()->getPage()->findById('loginForm')->submit(); - $this->mink->getSession()->wait(2500); // wait 2.5 seconds for page to load - $assert = $this->mink->assertSession(); - $assert->pageTextContains('Dashboard'); - } -} diff --git a/tests/integrations/bootstrap/FeatureContext.php b/tests/integrations/bootstrap/FeatureContext.php new file mode 100644 index 00000000..2719c925 --- /dev/null +++ b/tests/integrations/bootstrap/FeatureContext.php @@ -0,0 +1,373 @@ +params = $parameters; + + if (null == getenv('BITPAY_EMAIL')) { + $this->email = $this->params['user']; + } else { + $this->email = getenv('BITPAY_EMAIL'); + } + if (null == getenv('BITPAY_PASSWORD')) { + $this->password = $this->params['password']; + } else { + $this->password = getenv('BITPAY_PASSWORD'); + } + + if (null == getenv('BITPAY_URL')) { + $this->base_url = $this->params['base_url']; + } else { + $this->base_url = getenv('BITPAY_URL'); + } + + $port = parse_url($this->base_url, PHP_URL_PORT); + if (true == is_null(parse_url($this->base_url, PHP_URL_PORT))) { + $this->port = 443; + $this->port_required_in_url = false; + } else { + $this->port = parse_url($this->base_url, PHP_URL_PORT); + $this->port_required_in_url = true; + } + + if (parse_url($this->base_url, PHP_URL_HOST) == 'test.bitpay.com') { + $this->network = new \Bitpay\Network\Testnet(); + } else { + $url = parse_url($this->base_url, PHP_URL_HOST); + $this->network = new \Bitpay\Network\Customnet($url, $this->port, $this->port_required_in_url); + } + + if ((null == $this->email) || (null == $this->password)) { + throw new Exception("Your email or password are not configured."); + return; + } + + if (null == $this->base_url) { + throw new Exception("Your url is not configured."); + return; + } + + $phantomjsDriver = new \Behat\Mink\Driver\Selenium2Driver('phantomJS', null, 'http://127.0.0.1:8643'); + $selenium2Driver = new \Behat\Mink\Driver\Selenium2Driver('firefox'); + + $this->mink = new \Behat\Mink\Mink( + array( + 'phantomjs' => new \Behat\Mink\Session($phantomjsDriver), + 'selenium2' => new \Behat\Mink\Session($selenium2Driver), + ) + ); + + $this->mink->setDefaultSessionName($this->params['driver']); + } + + /** + * @Given /^the user is authenticated with BitPay$/ + */ + public function theUserIsAuthenticatedWithBitpay() + { + if(true == !file_exists('/tmp/token.json') || true == !file_exists('/tmp/bitpay.pri') || true == !file_exists('/tmp/bitpay.pub')){ + $this->theUserPairsWithBitpayWithAValidPairingCode(); + $this->theUserIsPairedWithBitpay(); + } + } + + /** + * @When /^the user creates an invoice for "([^"]*)" "([^"]*)"$/ + */ + public function theUserCreatesAnInvoiceFor($price, $currency) + { + try { + // Load keys + list($privateKey, $publicKey, $token_id) = loadKeys(); + + $network = $this->network; + $client = createClient($network, $privateKey, $publicKey); + + $token = new \Bitpay\Token(); + $token->setToken($token_id); + $client->setToken($token); + + $invoice = new \Bitpay\Invoice(); + + $item = new \Bitpay\Item(); + $item + ->setCode('skuNumber') + ->setDescription('General Description of Item') + ->setPrice($price); + $invoice->setItem($item); + + $invoice->setCurrency(new \Bitpay\Currency($currency)); + $client->createInvoice($invoice); + $this->response = $client->getResponse(); + $body = $this->response->getBody(); + $json = json_decode($body, true); + $this->invoiceId = $json['data']['id']; + } catch (\Exception $e) { + $this->error = $e; + } finally { + return true; + } + } + + /** + * @Then /^they should recieve an invoice in response for "([^"]*)" "([^"]*)"$/ + */ + public function theyShouldRecieveAnInvoiceInResponseFor($price, $currency) + { + $body = $this->response->getBody(); + $json = json_decode($body, true); + $responsePrice = (string) $json['data']['price']; + $responseCurrency = $json['data']['currency']; + if ($responsePrice !== $price){ + throw new Exception("Error: Price is different", 1); + } + if ($responseCurrency !== $currency){ + throw new Exception("Error: Currency is different", 1); + } + } + + /** + * @Given /^the user pairs with BitPay with a valid pairing code$/ + */ + public function theUserPairsWithBitpayWithAValidPairingCode() + { + // Login + + $this->mink->getSession()->visit($this->base_url.'/merchant-login'); + + $this->mink->getSession()->wait(1500); + $this->mink->getSession()->getPage()->fillField('email', $this->email); + $this->mink->getSession()->getPage()->fillField('password', $this->password); + + $value = $this->mink->getSession()->getPage()->pressButton('loginButton'); + + $this->mink->getSession()->wait(2500); + + $assert = $this->mink->assertSession(); + $assert->pageTextContains('Dashboard'); + + // Navigate to tokens + $this->mink->getSession()->wait(1500); + $this->mink->getSession()->getPage()->clickLink('My Account'); + $this->mink->getSession()->wait(1500); + $this->mink->getSession()->getPage()->clickLink('API Tokens'); + $this->mink->getSession()->wait(1500); + + // Create and set pairing code + $cssSelector = ".icon-plus"; + $element = $this->mink->getSession()->getPage()->find( + 'xpath', + $this->mink->getSession()->getSelectorsHandler()->selectorToXpath('css', $cssSelector) // just changed xpath to css + ); + if (null === $element) { + throw new \InvalidArgumentException(sprintf('Could not evaluate CSS Selector: "%s"', $cssSelector)); + } + $element->press(); + + $this->mink->getSession()->wait(1500); + $this->mink->getSession()->getPage()->pressButton("Add Token"); + $this->mink->getSession()->wait(5000); + + $this->validPairingCode = $this->mink->getSession()->getPage()->find('xpath', '//*[@id="my-token-access-wrapper"]/div[1]/div[2]/div/div')->getText(); + } + + /** + * @Then /^the user is paired with BitPay$/ + */ + public function theUserIsPairedWithBitpay() + { + // Create Keys + list($privateKey, $publicKey, $sinKey) = generateAndPersistKeys(); + + //Set Client + $network = $this->network; + $client = createClient($network, $privateKey, $publicKey); + + $pairingCode = $this->validPairingCode; + + // Pair + try { + $token = $client->createToken( + array( + 'pairingCode' => $pairingCode, + 'label' => 'Integrations Testing', + 'id' => (string) $sinKey, + ) + ); + $token_file = fopen('/tmp/token.json', 'w'); + fwrite($token_file, $token); + fclose($token_file); + } catch (\Exception $e) { + $request = $client->getRequest(); + $response = $client->getResponse(); + echo (string) $request.PHP_EOL.PHP_EOL.PHP_EOL; + echo (string) $response.PHP_EOL.PHP_EOL; + exit(1); + } + + } + + /** + * @Given /^the user fails to pair with a semantically (?:in|)valid code "([^"]*)"$/ + */ + public function theUserFailsToPairWithASemanticallyValidCode($pairingCode) + { + try { + // Stupid rate limiters + $this->mink->getSession()->wait(1500); + + // Create Keys + list($privateKey, $publicKey, $sinKey) = generateAndPersistKeys(); + + //Set Client + $network = $this->network; + $client = createClient($network, $privateKey, $publicKey); + + // Pair + $token = $client->createToken( + array( + 'pairingCode' => $pairingCode, + 'label' => 'Integrations Testing', + 'id' => (string) $sinKey, + ) + ); + } catch (\Exception $e) { + $this->error = $e; + } finally { + return true; + } + + } + + /** + * @Then /^they will receive a "([^"]*)" matching \'([^\']*)\'$/ + */ + public function theyWillReceiveAnErrorMatching($expectedErrorName, $expectedErrorMessage) + { + $curlError = $this->error; + $curlErrorMessage = $this->error->getMessage(); + if (strpos($curlErrorMessage, $expectedErrorMessage) === false) { + throw new Exception("Error message incorrect: ".$curlErrorMessage, 1); + } + if (strpos(get_class($curlError), $expectedErrorName) === false) { + throw new Exception("Error name incorrect: ".get_class($curlError), 1); + } + } + + /** + * @When /^the client fails to pair with BitPay because (open|closed) port ([0-9]+) is an incorrect port$/ + */ + public function theClientFailsToPairWithBitpayBecauseOfAnIncorrectPort($status, $port) + { + try { + // Stupid rate limiters + $this->mink->getSession()->wait(1500); + + // Create Keys + list($privateKey, $publicKey, $sinKey) = generateAndPersistKeys(); + + //Set Client + $url = parse_url($this->base_url, PHP_URL_HOST); + $network = new \Bitpay\Network\Customnet($url, $port, true); + $curl_options = array( + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_SSL_VERIFYHOST => false, + CURLOPT_TIMEOUT => 5, + ); + $client = createClient($network, $privateKey, $publicKey, $curl_options); + + // Pair + $token = $client->createToken( + array( + 'pairingCode' => 'aaaaaaa', + 'label' => 'Integrations Testing', + 'id' => (string) $sinKey, + ) + ); + } catch (\Exception $e) { + $this->error = $e; + } finally { + return true; + } + } + + /** + * @Given /^that a user knows an invoice id$/ + */ + public function thatAUserKnowsAnInvoiceId() + { + if(true == !file_exists('/tmp/token.json') || true == !file_exists('/tmp/bitpay.pri') || true == !file_exists('/tmp/bitpay.pub')){ + $this->theUserPairsWithBitpayWithAValidPairingCode(); + $this->theUserIsPairedWithBitpay(); + } + $this->theUserCreatesAnInvoiceFor(1.99, 'USD'); + } + + /** + * @Then /^they can retrieve that invoice$/ + */ + public function theyCanRetrieveThatInvoice() + { + try + { + $network = $this->network; + $client = createClient($network); + $response = $client->getInvoice($this->invoiceId); + } catch (Exception $e){ + var_dump($e->getMessage()); + } + $responseInvoiceId = $response->getId(); + if($responseInvoiceId !== $this->invoiceId){ + throw new Exception("Invoice ids don't match"); + } + } +} \ No newline at end of file diff --git a/tests/integrations/bootstrap/StepHelper.php b/tests/integrations/bootstrap/StepHelper.php new file mode 100644 index 00000000..9f9bd000 --- /dev/null +++ b/tests/integrations/bootstrap/StepHelper.php @@ -0,0 +1,54 @@ +generate(); + $publicKey = new \Bitpay\PublicKey('/tmp/bitpay.pub'); + $publicKey->setPrivateKey($privateKey); + $publicKey->generate(); + $sinKey = new \Bitpay\SinKey('/tmp/sin.key'); + $sinKey->setPublicKey($publicKey); + $sinKey->generate(); + + //Persist Keys + $storageEngine = new \Bitpay\Storage\EncryptedFilesystemStorage('YourTopSecretPassword'); + $storageEngine->persist($privateKey); + $storageEngine->persist($publicKey); + + return array($privateKey, $publicKey, $sinKey); +} + +function loadKeys() +{ + $storageEngine = new \Bitpay\Storage\EncryptedFilesystemStorage('YourTopSecretPassword'); + $privateKey = $storageEngine->load('/tmp/bitpay.pri'); + $publicKey = $storageEngine->load('/tmp/bitpay.pub'); + $token_id = file_get_contents('/tmp/token.json'); + + return array($privateKey, $publicKey, $token_id); +} + +function createClient($network, $privateKey = null, $publicKey = null, $curl_options = null) +{ + if(true === is_null($curl_options)) { + $curl_options = array( + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_SSL_VERIFYHOST => false, + ); + } + $adapter = new \Bitpay\Client\Adapter\CurlAdapter($curl_options); + $client = new \Bitpay\Client\Client(); + + if(true === !is_null($privateKey)) { + $client->setPrivateKey($privateKey); + } + if(true === !is_null($publicKey)) { + $client->setPublicKey($publicKey); + } + + $client->setNetwork($network); + $client->setAdapter($adapter); + + return $client; +} \ No newline at end of file diff --git a/tests/integrations/invoice_create.feature b/tests/integrations/invoice_create.feature new file mode 100644 index 00000000..31d477be --- /dev/null +++ b/tests/integrations/invoice_create.feature @@ -0,0 +1,29 @@ +#create_invoices.feature +Feature: creating an invoice + The user won't get any money + If they can't + Create Invoices + + Background: + Given the user is authenticated with BitPay + + @javascript + Scenario Outline: The request is correct + When the user creates an invoice for + Then they should recieve an invoice in response for + Examples: + | price | currency | + | "1.01" | "USD" | + | "1.01" | "EUR" | + + @javascript + Scenario Outline: The invoice contains illegal characters + When the user creates an invoice for + Then they will receive a "Bitpay\Client\ArgumentException" matching + Examples: + | price | currency | message | + | "1,023" | "USD" | 'Price must be formatted as a float' | + | "1.21" | "EaUR" | 'The currency code "EaUR" is not supported.' | + | "" | "USD" | 'Price must be formatted as a float' | + | "Ten" | "USD" | 'Price must be formatted as a float' | + | "1" | "" | 'The currency code "" is not supported.' | diff --git a/tests/integrations/invoice_retrieve.feature b/tests/integrations/invoice_retrieve.feature new file mode 100644 index 00000000..199fb8a6 --- /dev/null +++ b/tests/integrations/invoice_retrieve.feature @@ -0,0 +1,9 @@ +#retrieve_invoices.feature +Feature: retrieving an invoice + The user may want to retrieve invoices + So that they can view them + + @javascript + Scenario: The request is correct + Given that a user knows an invoice id + Then they can retrieve that invoice \ No newline at end of file diff --git a/tests/integrations/pairing.feature b/tests/integrations/pairing.feature new file mode 100644 index 00000000..e61af273 --- /dev/null +++ b/tests/integrations/pairing.feature @@ -0,0 +1,28 @@ +# pairing.feature +Feature: pairing with bitpay + In order to access bitpay + It is required that the library + Is able to pair successfully + + @javascript + Scenario: the client has a correct pairing code + Given the user pairs with BitPay with a valid pairing code + Then the user is paired with BitPay + + @javascript + Scenario Outline: the client has a bad pairing code + Given the user fails to pair with a semantically code + Then they will receive a matching + Examples: + | valid | code | error | message | + | valid | "a1b2c3d" | "Bitpay\Client\BitpayException" | '500: Unable to create token' | + | invalid | "a1b2c3d4" | "Bitpay\Client\ArgumentException" | 'pairing code is not legal' | + + @javascript + Scenario Outline: the client has a bad port configuration to an incorrect port + When the client fails to pair with BitPay because port is an incorrect port + Then they will receive a matching + Examples: + | status | port | error | message | + | open | 444 | "Bitpay\Client\ConnectionException" | 'timed out' | + | closed | 8444 | "Bitpay\Client\ConnectionException" | 'Connection refused' | \ No newline at end of file