Giter VIP home page Giter VIP logo

stripity-stripe's People

Contributors

ascandella avatar asummers avatar begedin avatar davidantaramian avatar deepwalker avatar dkulchenko avatar dmvt avatar dnsbty avatar esse avatar freedomben avatar gmile avatar he9lin avatar jayjun avatar joshsmith avatar juljimm avatar kerryjj avatar maartenvanvliet avatar mcrumm avatar nicrioux avatar pragmaticivan avatar robconery avatar sb8244 avatar schrockwell avatar snewcomer avatar sylver avatar tlvenn avatar tylerwray avatar web-flow avatar williamhogman avatar yordis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stripity-stripe's Issues

Can not run mix.deps.get

Can not rune mix.deps.get in my project.
This is my file Mix.config

defmodule Delivr.Mixfile do
  use Mix.Project

  def project do
    [app: :delivr,
     version: "0.0.1",
     elixir: "~> 1.2",
     elixirc_paths: elixirc_paths(Mix.env),
     compilers: [:phoenix, :gettext] ++ Mix.compilers,
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     aliases: aliases(),
     deps: deps()]
  end

  # Configuration for the OTP application.
  #
  # Type `mix help compile.app` for more information.
  def application do
    [mod: {Delivr, []},
     applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext,
                    :phoenix_ecto, :postgrex, :sendgrid, :calendar, :stripity_stripe]]
  end

  # Specifies which paths to compile per environment.
  defp elixirc_paths(:test), do: ["lib", "web", "test/support"]
  defp elixirc_paths(_),     do: ["lib", "web"]

  # Specifies your project dependencies.
  #
  # Type `mix help deps` for examples and options.
  defp deps do
    [{:phoenix, "~> 1.2.0"},
     {:phoenix_pubsub, "~> 1.0"},
     {:phoenix_ecto, "~> 3.0"},
     {:postgrex, ">= 0.0.0"},
     {:phoenix_html, "~> 2.6"},
     {:phoenix_live_reload, "~> 1.0", only: :dev},
     {:gettext, "~> 0.11"},
     {:cowboy, "~> 1.0"},
     {:exrm, "~> 1.0.6"},
     {:timex, "~> 2.1.0"},
     {:timex_ecto, "~> 1.1.0"},
     {:number, "~> 0.4.2"},
     {:httpoison, "~> 0.9.0"},
     {:floki, "~> 0.9.0"},
     {:sendgrid, "~> 1.0.2"},
     {:hashids, "~> 2.0"},
     {:json, "~> 0.3.0"},
     {:calendar, "~> 0.14.2"},
     {:stripity_stripe, "~> 1.4.0"}]
  end

  # Aliases are shortcuts or tasks specific to the current project.
  # For example, to create, migrate and run the seeds file at once:
  #
  #     $ mix ecto.setup
  #
  # See the documentation for `Mix` for more info on aliases.
  defp aliases do
    ["ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
     "ecto.reset": ["ecto.drop", "ecto.setup"],
     "test": ["ecto.create --quiet", "ecto.migrate", "test"]]
  end
end

This is my error

Failed to use "hackney" (version 1.6.1) because
  httpoison (version 0.9.0) requires ~> 1.6.0
  stripity_stripe (version 1.4.0) requires ~> 1.4.8
  tzdata (version 0.5.8) requires ~> 1.0
  Locked to 1.6.1 in your mix.lock

** (Mix) Hex dependency resolution failed, relax the version requirements of your dependencies or unlock them (by using mix deps.update or mix deps.unlock)

Replace dicts with maps

We should generally update the codebase wherever possible to replace dicts with maps where it makes sense:

  • Identify lines that could be replaced
  • Propose a good replacement
  • Make the replacements

RFC - Stripity Stripe 2.0

Start Date: 2016-10-19

Summary

Stripity Stripe is in need of an upgrade to provide a more flexible Elixir wrapper for the amazing Stripe API. There are two main goals of this rewrite. First, Stripity Stripe 2.0 should have a consistent and easy to understand high level API. Given that Elixir was born of Ruby, we will seek to closely match the documented Ruby Interface. Second, there should be full test coverage which does not rely on recorded responses of a specific version of the API. We want to be testing our functionality, not that of the Stripe API itself.

Motivation

The initial desire for 2.0 came out of a conversation between Dan Matthews of Strumber and Josh Smith of Code Corps. Both teams were/are implementing on top of Stripe's Connect functionality and found the existing version's endpoint modules to be generally lacking best practice support for the Stripe-Account header. Additionally, we discovered unnecessary dependencies, unsupported endpoints, inconsistent variable names and a good deal of repetition.

Rob Conery was gracious enough to hand us the reins several days ago.

Detailed design

HTTPoison will be replaced with Hackney at the suggestion of @DavidAntaramian in Issue #100. Along this thought line, dependencies should be generally avoided unless absolutely necessary. Whenever possible, the lowest level dependency should be used.

Stripe provides a common endpoint structure for each primary endpoint. We will attempt to handle the majority of them through the use of common modules supplemented by heavy documentation. An example of this is as follows:

defmodule Stripe.Customers do
  @moduledoc """
  High Level API for working with Stripe Customers.

  Through this API you can:
  -Create a customer [ref](https://stripe.com/docs/api#create_customer)
  -Retrieve a customer [ref](https://stripe.com/docs/api#retrieve_customer)
  -Update a customer [ref](https://stripe.com/docs/api#update_customer)
  -Delete a customer [ref](https://stripe.com/docs/api#delete_customer)
  -List all customers [ref](https://stripe.com/docs/api#list_customers)
  """

  @endpoint "/customers"

  @doc """
  Creates a Customer. Valid attributes can be found in the
  [Stripe API Customer Docs](https://stripe.com/docs/api#create_customer).
  At the time of this writing, all were optional.

  [ref](https://stripe.com/docs/api#create_customer)

  ## Example
  `` `
    attributes = %{
      email: "[email protected]",
      description: "Customer for [email protected]",
      source: "tok_18pPRnBMvBFPIRGmeLiOEwlm"
    }

    {:ok, customer} = Stripe.Customers.create(attributes)
  `` `
  """

  use Stripe.API.Create

  @doc """
  Retrieves a Customer by ID.

  [ref](https://stripe.com/docs/api/ruby#retrieve_customer)

  ## Example
  `` `
  {:ok, customer} = Stripe.Customers.retrieve("cus_9McRYFr9fAGdKm")
  # or
  {:ok, customer} = Stripe.Customers.retrieve(%{id: "cus_9McRYFr9fAGdKm"})
  `` `
  """

  use Stripe.API.Retrieve

  # ...
end  

We will also only provide functions documented in the official Stripe API libraries. No additional functions are allowed directly on the High Level API modules.

Some endpoints have dependency ids in their URLs. These values will be extracted from the attributes map.

defmodule Stripe.Card do
  @endpoint "/customers/{customer_id}/sources"

  # ...
end
attributes = %{
  id: "card_196RVbBMvBFPIRGmREqyLEUh",
  customer_id: "cus_9McRYFr9fAGdKm"
}

{:ok, customer} = Stripe.Card.retrieve(attributes)

All public functions on High Level API modules have an arity of 4, the last 3 of which are optional.

def create(
  attributes,
  headers \\ %{},
  hackney_options \\ %{},
  secret_key \\ ""
) do
  # ...
end

Drawbacks

There is next to no backwards compatibility with Stripity Stripe Version 1. We're singularizing nearly every module name (Stripe.Customers becomes Stripe.Customer), leaving out (moving?) courtesy functions such as all and changing the arity of almost every function that is kept.

We're also intentionally treating fewer dependancies and DRYness as higher priority concerns than code readability when we choose to use Erlang modules such as Hackney directly, abandoning the syntactic sugar and familiarity of their Elixir wrappers. This choice may deter wider contributions in those areas of the code.

Unresolved questions

Should we provide some or all of the non-standard functions from version 1 in a Stripe.Utils module? The main one I personally find useful is the all function which iterates over the list endpoint.

Dependency resolution failing for 1.4.0

I added `{:stripity_stripe, "~> 1.4.0"} to my mix.exs, but dependency resolution is failing:

mix deps.get
Running dependency resolution

Failed to use "hackney" because
  stripity_stripe (version 1.4.0) requires ~> 1.4.8
  mix.lock specifies 1.6.2

Not sure why this it says it requires ~> 1.4.8, since the stripity-stripe mix.lock file says:

"hackney": {:hex, :hackney, "1.6.1", ...}

Bitcoin receiver

Anyone wanting to tackle this? I'm on the canadian side and don't have a US account yet. The feature is still limited to the US accounts. I want to be ready to use that feature as soon as I can + it would be a nice addition feature-wise.

Thoughts?

Fix URI Borked Tests

The URI Encoding tests use multiple assertions per test, which makes it difficult to understand what's going on. There's also a test failure that needs to be fixed.

Values are not escaped properly

Using v1.3.0.

If I submit a Stripe.Charge with an ampersand in the description field, I would expect this library to properly escape values to submit via the API.

This is a pretty serious issue leaving the library open to query-parameter injection / tampering.

Example:

{:ok, uncaptured_payment} = Stripe.Charges.create(amount, [
      capture: false,
      description: "Item1 & Item2",
      receipt_email: appointment.client.email,
      customer: appointment.client.stripe_customer_id,
      source: card_id,
      metadata: %{
        business_id: business.id,
        appointment_id: appointment.id,
        client_name: appointment.client.first_name <> " " <> appointment.client.last_name
      }
    ])
** (MatchError) no match of right hand side value: {:error, %{"error" => %{"message" => "Received unknown parameter:  Item2", "param" => " Item2", "type" => "invalid_request_error"}}}

Test suite hangs

โฏ STRIPE_SECRET_KEY=mykey mix test --trace
Excluding tags: [disabled: true]

warning: this check/guard will always yield the same result
  test/stripe/connect_test.exs:50

warning: this check/guard will always yield the same result
  test/stripe/stripe_test.exs:40


Stripe.SubscriptionTest

It just hangs there. I waited over 4 minutes before aborting.

(Elixir 1.3.1, OS X 10.11.6)

List invoices of specific customer

I am looking for a way to list invoices of a given customer. (https://stripe.com/docs/api/ruby#list_invoices)

Looking at the documentation, my first guess was that Stripe.Invoices.list might be usable for this purpose, but as far as I can see this function does not take customer id as a (optional) parameter.

Stripe.Invoices.get specifies the following (as an example):
{:ok, cust} = Stripe.Invoices.get "customer_id", key
Which looks promising, but it seems to be a copy-paste error from some other part of the documentation as Stripe.Invoice.get actually takes an invoice-id and not a customer-id as parameter.

Looking in the source code for the Stripe.Invoices module (https://github.com/code-corps/stripity-stripe/blob/master/lib/stripe/invoices.ex) I can see that there is an commented-out function called "get_invoices". This seemed to be what I was looking for at first glance, but as mentioned this function has been commented out and just copy-pasting the function (to make my own implementation) won't work:


#def get_invoices(id, params, key) do
#  params = Keyword.put_new params, :limit, 10  #params are never used
#  params = Keyword.put_new params, :customer, id #params are never used
#  Stripe.Util.list "invoices", key, starting_after, limit #params not used
#end

Params containing the customer id is never used (Stripe.Util.list does not support a params keyword list).

So how does one get a list of invoices for a specific customer?

Improve descriptiveness of tests

  • Identify tests that are lacking much explanation.
  • Open issues for individual tests
  • Rewrite those tests to improve their descriptiveness

Stripe.URI Efficiency

The Stripe.URI module code should be reviewed. It's a small issue, but right now it uses ++ with the left operand as the accumulator and the right operand as the added value. ++ is implemented such that the left operand is always copied, so our accumulator is always copied (which is what we don't want). See The Eight Myths of Erlang Performance

Proposal: Expose headers to class functions for Connect usage

When acting on behalf of a Connected account, Stripe recommends using the Stripe-Account header as seen here: https://stripe.com/docs/connect/payments-fees#charging-directly

I propose updating the class functions to expose headers in the following way:

This:

  def create(params, key) do
    Stripe.make_request_with_key(:post, @endpoint, key, params)
    |> Stripe.Util.handle_stripe_response
  end

would become this:

  def create(params, key_or_headers) when is_bitstring(key_or_headers) do
    Stripe.make_request_with_key(:post, @endpoint, key_or_headers, params)
    |> Stripe.Util.handle_stripe_response
  end

  def create(params, key_or_headers) when is_map(key_or_headers) do
    Stripe.make_request_with_key(
      :post, @endpoint, Stripe.config_or_env_key, params, key_or_headers
    )
    |> Stripe.Util.handle_stripe_response
  end

This still allows a key override but also supports passing any headers required without using the low level API on the Stripe class. With your approval, I'll submit a PR in the next week or so.

Replace HTTPoison with Hackney

HTTPoison doesn't offer any benefits over using Hackney directly, and it just adds another dependency to pin against; often times the use of HTTPoison will obfuscate the lower level support provided by Hackney. I would recommend swapping out HTTPoison for Hackney, which is a very simple process. I'm willing to do it if we're in agreement.

Stripe.Connect for managed accounts

Hey,
I see there is a Connect module implemented for standalone accounts and I was wondering if you are planning on adding managed accounts to the connect module?

Thanks,
Alaister

Update hex package

To use your latest version, github needs to be referenced, like this:

{:stripity_stripe, "~> 1.0.0", github: "robconery/stripity-stripe"},

Last hex package is 0.5.0 (it may also make sense to bump httpoison dependency to 0.8.0 - I had to downgrade my dependency in mix.exs).

What is being supervised?

I'm trying to advise someone on how to use this library, but I don't understand why you're starting a supervision tree. When I actually open the supervisor module's definition, nothing is being supervised. And from what I can tell, no children are ever dynamically added to the supervision tree.

You're also informing consumers that they need to insert Stripe into their own supervision tree, but that's incorrect as you have already started a supervision tree for the application which exists external the to the consumer's application at run-time.

As far as I can tell, a consumer should only have to add :stripity_stripe to their applications list, solely to have the application controller load :httpoison as an application. This also means there's no need to call HTTPoison.start/1 inside your code since this will be handled by ERTS/BEAM.

I'd appreciate pointers on why it's necessary to start a supervisor and what actually is being supervised. Thanks!

Subscriptions.change() something other than plan id error

With Subscriptions.change() I am unable to change other options (something other than the plan id) of a subscription.

This causes Stripe(.com) to return an error message:

Stripe.Subscriptions.change(user.stripe_customer_id, sub_id, [quantity: 3])
...
%{"error" => %{"message" => "Invalid string: {\"quantity\"=>\"3\"}",
    "param" => "plan", "type" => "invalid_request_error"}}

This works:

Stripe.make_request_with_key(
  :post,
  "customers/#{user.stripe_customer_id}/subscriptions/#{sub_id}",
  Stripe.config_or_env_key,
  [quantity: 3]
) |> Stripe.Util.handle_stripe_response

Assign multiple cards (tokens) to an existing customer

Hi There,

Please forgive me for posting a question here. Is there a way to assign multiple credit cards to an existing customer?

URL:
/v1/customers//sources

Parsed Request POST Body
{
card: "tok_17sFEyDzqcXKnkcafX4jkf2s"
}

Response body
{
id: card_17sFEyDzqcXKnkcaO95Kg2iY
object: "card"
address_city: null
address_country: null
address_line1: null
address_line1_check: null
address_line2: null
address_state: null
address_zip: null
address_zip_check: null
brand: "MasterCard"
country: "US"
customer: cus_88S0F9EAp18omi
cvc_check: "pass"
dynamic_last4: null
exp_month: 3
exp_year: 2017
fingerprint: "Pj4eCYNJpZuIHY9i"
funding: "credit"
last4: "4444"
metadata:
name: null
tokenization_method: null
}

Dependency Resolution Failed

Failed to use "hackney" because
  stripity_stripe (version 1.4.0) requires ~> 1.4.8
  Locked to 1.6.1 in your mix.lock

Is the solution to use the override: true option in my mix.exs?

Multiple test env

We should be able to mock the requests and also if we specify, run all the tests directly into stripe. So that way we're going to be able to use Travis CI.

error connecting

Hello,
I'm brand new to elixir, so pretty sure I'm doing something wrong.

I added config :usestripe, secret_key: "sk_test_XXX"
to config/config.exs

usestripe_test.exs look like:

defmodule UsestripeTest do
  use ExUnit.Case
  doctest Usestripe

  test "Customers are listed" do
    {:ok, customers} = Stripe.Customers.list
    assert length(customers) > 0
  end
end

test_helper.exs looks like:

ExUnit.start()
Stripe.start

mix test results in:

 $ mix test


  1) test Customers are listed (UsestripeTest)
     test/usestripe_test.exs:5
     ** (MatchError) no match of right hand side value: 
{:error, "You did not provide an API key, though you did set your Authorization header to \"Bearer\". 
Using Bearer auth, your Authorization header should look something like 'Authorization: Bearer 
YOUR_SECRET_KEY'. See https://stripe.com/docs/api#authentication for details, or we can help at 
https://support.stripe.com/."}
     stacktrace:
       test/usestripe_test.exs:6



Finished in 0.7 seconds (0.05s on load, 0.7s on tests)
1 test, 1 failure

Randomized with seed 333290

What am I missing? On elixir v1.1.0

Ensure all URLs are properly escaped

We should do a runthrough of this package to:

  • Identify any place where URLs lack proper escaping
  • Apply proper escaping to those URLs

If we don't find any, then we can just close this issue.

Mock Stripe within tests

Right now many of the tests either hit Stripe or have VCR cassettes. The more mocking or dependency injection or any other technique we can use to reduce the external reliance on hitting Stripe, the better.

General Code Cleanup

Broad issue name, but the codebase is old and it shows. I'd like to clean things up, move to v2 and see if we can streamline some things.

README should explain how to add to supervision tree

For the life of me I can't figure out what I have to do to get this working in my app. Explicitly calling Stripe.start works great, but in my app's supervisor, what am I supposed to add as the worker? Can you address this in the readme please?

List charges with params not working

When I try to list charges with anything other than a integer limit it throws and error thats not very useful in tracking down whats happening.

Stripe.Charges.list(customer: "customer_number")
** (ArgumentError) cannot convert the given list to a string.

To be converted to a string, a list must contain only:

  * strings
  * integers representing Unicode codepoints
  * or a list containing one of these three elements

Please check the given list or call inspect/1 to get the list representation, got:

[customer: "customer_number"]

             (elixir) lib/list.ex:624: List.to_string/1
    (stripity_stripe) lib/stripe/charges.ex:87: Stripe.Charges.list/2

any idea whats going on?

Support Committments

Primarily for @joshsmith: what are your support commitments for non-current versions of Elixir? The latest Elixir release is 1.3, and I would say that 1.2 is the farthest back things should be supported, as 1.2 released a lot of improvements for the ecosystem.

Proposal: make key usage more consistent

Right now there are basically two occurrences of the same method:

  1. one with API key,
  2. one without API key (relying on API key from configuration).

This means that we have to have:

  1. two actual functions in the source code doing the same thing, with one simply calling another,
  2. two documentation blocks describing essentially the same thing (with exception to the "with explicit key" function, telling it's possible to use the key),
  3. two test testing the same things (implying two cassettes, unless both methods are specified to use the same cassette as in #66).

I think this can be significantly improved & cleaned up:

  1. Leave only a single instance of each function implementing a single API call,
  2. Leave only a single block with docs,
  3. Refactor the usage of keys: push the decision of whether or not to use the key โ€“ down to make_request_with_key/1.

Example

Current implementation of Stripe.Customer.get is done with two functions:

@doc """
Retrieves a given Customer with the specified ID. Returns 404 if not found.
## Example

{:ok, cust} = Stripe.Customers.get "customer_id"

"""
def get(id) do
  get id, Stripe.config_or_env_key
end

@doc """
Retrieves a given Customer with the specified ID. Returns 404 if not found.
Using a given stripe key to apply against the account associated.
## Example

{:ok, cust} = Stripe.Customers.get "customer_id", key

"""
def get(id, key) do
  Stripe.make_request_with_key(:get, "#{@endpoint}/#{id}", key)
  |> Stripe.Util.handle_stripe_response
end

This can be reduced to:

@doc """
Retrieves a given Customer with the specified ID. Returns 404 if not found. Custom can be used as a second optional argument.

## Examples

{:ok, customer} = Stripe.Customers.get("customer_id")
{:ok, customer} = Stripe.Customers.get("customer_id", custom_key)

"""
def get(id, key \\ nil) do
  Stripe.make_request_with_key(:get, "#{@endpoint}/#{id}", key)
  |> Stripe.Util.handle_stripe_response
end

With the above, Stripe.make_request_with_key function would check if the key passed is a nil, and if so โ€“ rely on configuration key.

Proposal: remove setup/teardown blocks from the tests

TL;DR. Let's stop making API calls in setup_all blocks. Running tests against real API will become much slower, but contribution and running tests locally / on travis will remain as fast as they are right now.

Right now adding new API tests is somewhat overly complicated. Below I will show what it took to add a test for Stripe.Subscription.change/4 (see #70):

  1. write the test,

  2. write the code that fixes it,

  3. run the test against actual API, say:

    STRIPE_SECRET_KEY=qr0yuBikLRa5yJkMGuEO4DNblKhEJqkw mix test test/stripe/subscription_test.exs:134
  4. the test will fail. Here's why:

    1. before test run, a setup_all block is executed,
    2. ExVCR intercepts API calls done in the setup block and substitutes them with canned responses from fixtures/subscription_test/setup.json.
    3. these responses were recorded a while ago, and entities (such as customer) in the responses are no longer active,
    4. the test, however, doesn't know that. it was a now-inactive customer and now-inactive subscription, and tries to perform an operation involving both.
    5. the test fails, obviously (as Stripe returns a response, saying that the request contained not existing / inactive entities).
  5. remove responses for the test in question (I just recorded it, but it contains invalid response), as well as setup/teardown;

    rm fixture/vcr_cassettes/subscription_test/{setup,teardown,general_change}.json
  6. run the test again (same as step 3),

  7. see the test succeed,

  8. cleanup now-changed setup/teardown cassettes:

    git checkout fixture/vcr_cassettes/subscription_test/{setup,teardown}.json
  9. re-run the test to see it fail again:

    1) test General change works (Stripe.SubscriptionTest)
       test/stripe/subscription_test.exs:134
       ** (ExVCR.RequestNotMatchError) Request did not match with any one in the current cassette: fixture/vcr_cassettes/subscription_test/general_change.json.
       Delete the current cassette with [mix vcr.delete] and re-record.
    
       stacktrace:
         lib/exvcr/handler.ex:142: ExVCR.Handler.raise_error_if_cassette_already_exists/1
         lib/exvcr/handler.ex:126: ExVCR.Handler.get_response_from_server/2
         (hackney) :hackney.request(:post, "https://api.stripe.com/v1/customers/cus_8y7pX6pDygSSFA/subscriptions/sub_8y7po6D0QD5y9V", [{"Authorization", "Bearer qr0yuBikLRa5yJkMGuEO4DNblKhEJqkw"}, {"Content-Type", "application/x-www-form-urlencoded"}, {"User-Agent", "Stripe/v1 stripity-stripe/1.4.0"}], "plan[quantity]=3", [])
         (httpoison) lib/httpoison/base.ex:396: HTTPoison.Base.request/9
         (stripity_stripe) lib/stripe.ex:95: Stripe.make_request_with_key/6
         (stripity_stripe) lib/stripe/subscriptions.ex:113: Stripe.Subscriptions.change/4
         test/stripe/subscription_test.exs:136: (test)
    
  10. based on the failure, adjust the cassette recorded for the test so it now relies on old entities from setup.json, e.g. make these changes:

    - "url": "https://api.stripe.com/v1/customers/cus_8y7pX6pDygSSFA/subscriptions/sub_8y7po6D0QD5y9V"
    + "url": "https://api.stripe.com/v1/customers/cus_8r2iLZ3me9G4hU/subscriptions/sub_8r2ikymYYXhIlq"

    and

    - "Authorization": "Bearer qr0yuBikLRa5yJkMGuEO4DNblKhEJqkw",
    + "Authorization": "Bearer non_empty_secret_key_string",

I think this can and should be changed. I'm proposing we get rid of making API calls in setup_all blocks throughout the suite. If we do this, and assume that each test lives on its own, contributing new tests and fixing existing tests, will become significantly easier.

Instead of following the procedure above, ideally I should be doing it this:

  1. write the test,
  2. write the code that fixes it,
  3. run the test (this will record new cassettes with responses),
  4. commit the new code, test & cassette.

To sum up:

  • Advantages:
    • writing a new code & tests becomes really faster,
    • fixing existing code & re-recording cassettes (if needed) will be easier,
    • test order will no longer matter โ€“ each test will truly live on its own,
    • tests will become explicit (I feel this is relatively weak point, but worth mentioning).
  • Drawbacks:
    • running the suite against live API will be much slower (given this will be ran relatively infrequent, it should be ok)
    • there will be more bootstrapping code in tests.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.