-
Notifications
You must be signed in to change notification settings - Fork 350
Cookbook: Record and reply requests (tape, vcr)
Tymon Tobolski edited this page Nov 11, 2022
·
3 revisions
Run tests against real endpoints for the first time, save responses into test/tapes
directory and then read from disk on next run.
# config/test.exs
config :tesla, MyClient, adapter: Tesla.Adapter.Tape
defmodule Tesla.Adapter.Tape do
@behaviour Tesla.Adapter
def call(env, opts) do
dir = opts[:dir] || "test/tapes"
adapter = opts[:adapter] || Tesla.Adapter.Httpc
file = Path.join(dir, key(env))
case read(file) do
{:ok, {:ok, status, headers, body}} ->
{:ok, %{env | status: status, headers: headers, body: body}}
{:ok, {:error, reason}} ->
{:error, reason}
{:error, :enoent} ->
response = adapter.call(env, [])
File.mkdir_p(dir)
write(file, response)
response
end
end
defp key(env) do
[
key_method(env.method),
key_url(env.url, env.query),
key_body(env.body)
]
|> Enum.filter(& &1)
|> Enum.join("_")
end
defp key_method(method), do: String.upcase(to_string(method))
defp key_url(url, query), do: String.replace(Tesla.build_url(url, query), ~r/[^a-z0-9]+/i, "_")
defp key_body(nil), do: nil
defp key_body(""), do: nil
defp key_body(body), do: Base.encode16(:crypto.hash(:md5, body))
defp read(file) do
case File.read(file) do
{:ok, data} -> {:ok, :erlang.binary_to_term(data)}
{:error, :enoent} -> {:error, :enoent}
end
end
defp write(file, response) do
data =
case response do
{:ok, %{status: status, headers: headers, body: body}} -> {:ok, status, headers, body}
{:error, reason} -> {:error, reason}
end
File.write(file, :erlang.term_to_binary(data))
end
end