Skip to content

Commit

Permalink
Write Pact consumer tests for account-api
Browse files Browse the repository at this point in the history
Pact consumer tests have a few different parts:

1. They define request/response templates (much like webmock, but with
a different DSL); this is the `before` blocks

2. They run the tests and complain if:
   - any unexpected requests are made
   - any defined requests aren't made

The templates are saved to a JSON file, which is used by the provider
tests (in this case, the account-api tests) to validate that the
provider returns matching outputs for the same inputs.

The "given" part of the set-up corresponds to a "provider state",
which is a named `before` block, run as part of the provider tests.
  • Loading branch information
barrucadu committed Mar 19, 2021
1 parent 6d4e303 commit 2141042
Show file tree
Hide file tree
Showing 2 changed files with 291 additions and 0 deletions.
278 changes: 278 additions & 0 deletions test/account_api_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
require "test_helper"
require "gds_api/account_api"

describe GdsApi::AccountApi do
include PactTest

let(:api_client) { GdsApi::AccountApi.new(account_api_host) }

let(:authenticated_headers) { { "GOVUK-Account-Session" => govuk_account_session } }
let(:govuk_account_session) { "logged-in-user-session" }

describe "getting a sign-in URL" do
let(:redirect_path) { nil }

before do
account_api
.upon_receiving("a sign-in request")
.with(
method: :get,
path: "/api/oauth2/sign-in",
headers: GdsApi::JsonClient.default_request_headers,
)
.will_respond_with(
status: 200,
headers: { "Content-Type" => "application/json; charset=utf-8" },
body: {
auth_uri: Pact.like("http://authentication-provider/some/oauth/url"),
state: Pact.like("value-to-use-for-csrf-prevention"),
},
)
end

it "responds with 200 OK, an authentication URI, and a state for CSRF protection" do
response = api_client.get_sign_in_url
assert response["auth_uri"].present?
assert response["state"].present?
assert_equal 200, response.code
end
end

describe "validating an OAuth response" do
before do
account_api
.given("there is a valid OAuth response")
.upon_receiving("a validation request")
.with(
method: :post,
path: "/api/oauth2/callback",
body: {
code: "code",
state: "state",
},
headers: GdsApi::JsonClient.default_request_with_json_body_headers,
)
.will_respond_with(
status: 200,
headers: { "Content-Type" => "application/json; charset=utf-8" },
body: {
govuk_account_session: Pact.like("user-session-id"),
},
)
end

it "responds with 200 OK and a govuk_account_session" do
response = api_client.validate_auth_response(code: "code", state: "state")
assert response["govuk_account_session"].present?
assert response["redirect_path"].nil?
assert_equal 200, response.code
end
end

describe "validating an OAuth response with a redirect path" do
let(:redirect_path) { "/some-arbitrary-path" }

before do
account_api
.given("there is a valid OAuth response, with the redirect path '/some-arbitrary-path'")
.upon_receiving("a validation request")
.with(
method: :post,
path: "/api/oauth2/callback",
body: {
code: "code",
state: "state",
},
headers: GdsApi::JsonClient.default_request_with_json_body_headers,
)
.will_respond_with(
status: 200,
headers: { "Content-Type" => "application/json; charset=utf-8" },
body: {
govuk_account_session: Pact.like("user-session-id"),
redirect_path: Pact.like(redirect_path),
},
)
end

it "responds with a redirect_path" do
response = api_client.validate_auth_response(code: "code", state: "state")
assert_equal redirect_path, response["redirect_path"]
end
end

describe "creating a registration state" do
let(:attributes) { { foo: "bar" } }

before do
account_api
.upon_receiving("a create-state request")
.with(
method: :post,
path: "/api/oauth2/state",
body: { attributes: attributes },
headers: GdsApi::JsonClient.default_request_with_json_body_headers,
)
.will_respond_with(
status: 200,
headers: { "Content-Type" => "application/json; charset=utf-8" },
body: {
state_id: Pact.like("reference-to-pass-to-get_sign_in_url"),
},
)
end

it "responds with 200 OK and a state_id" do
response = api_client.create_registration_state(attributes: attributes)
assert response["state_id"].present?
assert_equal 200, response.code
end
end

describe "checking for a transition checker email subscription" do
describe "the user is logged in" do
let(:given) { "there is a valid user session" }
let(:has_subscription) { false }

before do
account_api
.given(given)
.upon_receiving("a has-subscription request")
.with(
method: :get,
path: "/api/transition-checker-email-subscription",
headers: GdsApi::JsonClient.default_request_headers.merge(authenticated_headers),
)
.will_respond_with(
status: 200,
headers: { "Content-Type" => "application/json; charset=utf-8" },
body: {
govuk_account_session: Pact.like("user-session-id"),
has_subscription: has_subscription,
},
)
end

it "responds with 200 OK, a new govuk_account_session, and says that the subscription does not exist" do
response = api_client.check_for_email_subscription(govuk_account_session: govuk_account_session)
assert response["govuk_account_session"].present?
assert_equal false, response["has_subscription"]
assert_equal 200, response.code
end

describe "a subscription exists" do
let(:given) { "there is a valid user session, with a transition checker email subscription" }
let(:has_subscription) { true }

it "says that the subscription exists" do
response = api_client.check_for_email_subscription(govuk_account_session: govuk_account_session)
assert response["has_subscription"]
end
end
end
end

describe "setting the transition checker email subscription" do
describe "the user is logged in" do
before do
account_api
.given("there is a valid user session")
.upon_receiving("a set-subscription request")
.with(
method: :post,
path: "/api/transition-checker-email-subscription",
body: { slug: "brexit-emails-123" },
headers: GdsApi::JsonClient.default_request_with_json_body_headers.merge(authenticated_headers),
)
.will_respond_with(
status: 200,
headers: { "Content-Type" => "application/json; charset=utf-8" },
body: {
govuk_account_session: Pact.like("user-session-id"),
},
)
end

it "responds with 200 OK and a new govuk_account_session" do
response = api_client.set_email_subscription(govuk_account_session: govuk_account_session, slug: "brexit-emails-123")
assert response["govuk_account_session"].present?
assert_equal 200, response.code
end
end
end

describe "fetching attribute values" do
describe "the user is logged in" do
let(:given) { "there is a valid user session" }
let(:attributes) { {} }

before do
account_api
.given(given)
.upon_receiving("a get-attributes request")
.with(
method: :get,
path: "/api/attributes",
query: { "attributes[]" => %w[foo] },
headers: GdsApi::JsonClient.default_request_headers.merge(authenticated_headers),
)
.will_respond_with(
status: 200,
headers: { "Content-Type" => "application/json; charset=utf-8" },
body: {
govuk_account_session: Pact.like("user-session-id"),
values: attributes,
},
)
end

it "responds with 200 OK, a new govuk_account_session, and no attributes" do
response = api_client.get_attributes(govuk_account_session: govuk_account_session, attributes: %w[foo])
assert response["govuk_account_session"].present?
assert_equal attributes, response["values"]
assert_equal 200, response.code
end

describe "attributes exist" do
let(:given) { "there is a valid user session, with an attribute called 'foo'" }
let(:attributes) { { foo: { bar: "baz" } } }

it "responds with the attribute values" do
response = api_client.get_attributes(govuk_account_session: govuk_account_session, attributes: %w[foo])
assert_equal attributes[:foo][:bar], response["values"]["foo"]["bar"]
end
end
end
end

describe "setting attribute values" do
let(:attributes) { { foo: [1, 2, 3], bar: { nested: "json" } } }

describe "the user is logged in" do
before do
account_api
.given("there is a valid user session")
.upon_receiving("a set-attributes request")
.with(
method: :patch,
path: "/api/attributes",
body: { attributes: attributes.transform_values(&:to_json) },
headers: GdsApi::JsonClient.default_request_with_json_body_headers.merge(authenticated_headers),
)
.will_respond_with(
status: 200,
headers: { "Content-Type" => "application/json; charset=utf-8" },
body: {
govuk_account_session: Pact.like("user-session-id"),
},
)
end

it "responds with 200 OK and a new govuk_account_session" do
response = api_client.set_attributes(govuk_account_session: govuk_account_session, attributes: attributes)
assert response["govuk_account_session"].present?
assert_equal 200, response.code
end
end
end
end
13 changes: 13 additions & 0 deletions test/test_helpers/pact_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
PUBLISHING_API_PORT = 3001
ORGANISATION_API_PORT = 3002
BANK_HOLIDAYS_API_PORT = 3003
ACCOUNT_API_PORT = 3004

def publishing_api_host
"http://localhost:#{PUBLISHING_API_PORT}"
Expand All @@ -14,6 +15,10 @@ def bank_holidays_api_host
"http://localhost:#{BANK_HOLIDAYS_API_PORT}"
end

def account_api_host
"http://localhost:#{ACCOUNT_API_PORT}"
end

Pact.service_consumer "GDS API Adapters" do
has_pact_with "Publishing API" do
mock_service :publishing_api do
Expand All @@ -37,3 +42,11 @@ def bank_holidays_api_host
end
end
end

Pact.service_consumer "GDS API Adapters" do
has_pact_with "Account API" do
mock_service :account_api do
port ACCOUNT_API_PORT
end
end
end

0 comments on commit 2141042

Please sign in to comment.