From c47e42686276017a5acf597d9be92a3bbc0eeba4 Mon Sep 17 00:00:00 2001 From: John Wu Date: Fri, 21 Jul 2023 13:15:55 +0100 Subject: [PATCH] Add support for addresses --- changelog.md | 3 + lib/quaderno-ruby.rb | 3 +- lib/quaderno-ruby/address.rb | 10 ++ lib/quaderno-ruby/behavior/crud.rb | 1 - lib/quaderno-ruby/exceptions/exceptions.rb | 8 ++ lib/quaderno-ruby/helpers/response.rb | 13 ++ .../all_address_on_standard_account.yml | 63 +++++++++ .../all_addresses_by_authentication_token.yml | 67 +++++++++ .../found_address_by_access_token.yml | 129 +++++++++++++++++ .../found_address_by_authentication_token.yml | 128 +++++++++++++++++ .../new_address_by_access_token.yml | 70 +++++++++ .../new_address_by_authentication_token.yml | 70 +++++++++ .../updated_address_by_access_token.yml | 133 ++++++++++++++++++ ...pdated_address_by_authentication_token.yml | 132 +++++++++++++++++ spec/unit/test_quaderno_addresses.rb | 103 ++++++++++++++ 15 files changed, 931 insertions(+), 2 deletions(-) create mode 100644 lib/quaderno-ruby/address.rb create mode 100644 lib/quaderno-ruby/helpers/response.rb create mode 100644 spec/fixtures/quaderno_cassettes/all_address_on_standard_account.yml create mode 100644 spec/fixtures/quaderno_cassettes/all_addresses_by_authentication_token.yml create mode 100644 spec/fixtures/quaderno_cassettes/found_address_by_access_token.yml create mode 100644 spec/fixtures/quaderno_cassettes/found_address_by_authentication_token.yml create mode 100644 spec/fixtures/quaderno_cassettes/new_address_by_access_token.yml create mode 100644 spec/fixtures/quaderno_cassettes/new_address_by_authentication_token.yml create mode 100644 spec/fixtures/quaderno_cassettes/updated_address_by_access_token.yml create mode 100644 spec/fixtures/quaderno_cassettes/updated_address_by_authentication_token.yml create mode 100644 spec/unit/test_quaderno_addresses.rb diff --git a/changelog.md b/changelog.md index c47ed05..57b38a9 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,7 @@ ## 3.0.0 * Added support for accounts API +* Added support for addresses API * Added support for tax rates API * Added support for tax jurisdictions API * Added support for tax codes API @@ -9,6 +10,8 @@ * Phase out legacy `Quaderno::Tax` class in favour of `Quaderno::TaxRate` (the class will be removed in the next release) * Relaxed httparty requirements * Detect and handle `bad_request` response codes +* Added `Quaderno::Exceptions::InvalidRequest` to handle `not_acceptable` response codes +* Added `BaseException#response_body` to check the API response error ## 2.2.0 * Added support for transactions API diff --git a/lib/quaderno-ruby.rb b/lib/quaderno-ruby.rb index ad6a13a..1cc68cf 100644 --- a/lib/quaderno-ruby.rb +++ b/lib/quaderno-ruby.rb @@ -7,9 +7,10 @@ class Quaderno require 'quaderno-ruby/version' require 'quaderno-ruby/helpers/rate_limit' +require 'quaderno-ruby/helpers/response' require 'quaderno-ruby/exceptions/exceptions' require 'quaderno-ruby/helpers/authentication' require 'quaderno-ruby/collection' %w[block crud deliver payment retrieve].each { |filename| require "quaderno-ruby/behavior/#{filename}" } -%w[base account contact item transaction invoice receipt credit income estimate expense recurring document_item report report_request evidence payment webhook tax tax_id tax_rate tax_code tax_jurisdiction checkout_session].each { |filename| require "quaderno-ruby/#{filename}" } +%w[base account address contact item transaction invoice receipt credit income estimate expense recurring document_item report report_request evidence payment webhook tax tax_id tax_rate tax_code tax_jurisdiction checkout_session].each { |filename| require "quaderno-ruby/#{filename}" } diff --git a/lib/quaderno-ruby/address.rb b/lib/quaderno-ruby/address.rb new file mode 100644 index 0000000..688cf95 --- /dev/null +++ b/lib/quaderno-ruby/address.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class Quaderno::Address < Quaderno::Base + api_model Quaderno::Address + api_path 'addresses' + + class << self + undef :delete + end +end diff --git a/lib/quaderno-ruby/behavior/crud.rb b/lib/quaderno-ruby/behavior/crud.rb index b83d290..79ca48a 100644 --- a/lib/quaderno-ruby/behavior/crud.rb +++ b/lib/quaderno-ruby/behavior/crud.rb @@ -2,7 +2,6 @@ module Quaderno::Behavior module Crud - def self.included(receiver) receiver.send :extend, ClassMethods end diff --git a/lib/quaderno-ruby/exceptions/exceptions.rb b/lib/quaderno-ruby/exceptions/exceptions.rb index eb8655d..c2f26d8 100644 --- a/lib/quaderno-ruby/exceptions/exceptions.rb +++ b/lib/quaderno-ruby/exceptions/exceptions.rb @@ -1,6 +1,9 @@ +# frozen_string_literal: true + module Quaderno::Exceptions class BaseException < StandardError include Quaderno::Helpers::RateLimit + include Quaderno::Helpers::Response end class InvalidSubdomainOrToken < BaseException @@ -9,6 +12,9 @@ class InvalidSubdomainOrToken < BaseException class InvalidID < BaseException end + class InvalidRequest < BaseException + end + class RateLimitExceeded < BaseException end @@ -63,12 +69,14 @@ def check_exception_for(party_response, params = {}) raise_exception(Quaderno::Exceptions::HasAssociatedDocuments, party_response.body, party_response) end + raise_exception(Quaderno::Exceptions::InvalidRequest, 'Invalid request', party_response) if party_response.response.instance_of?(Net::HTTPNotAcceptable) raise_exception(Quaderno::Exceptions::ServerError, 'Server error', party_response) if party_response.response.is_a?(Net::HTTPServerError) end def raise_exception(klass, message, response) exception = klass.new(message) exception.rate_limit_info = response + exception.response_body = response.parsed_response raise exception end diff --git a/lib/quaderno-ruby/helpers/response.rb b/lib/quaderno-ruby/helpers/response.rb new file mode 100644 index 0000000..f3e5033 --- /dev/null +++ b/lib/quaderno-ruby/helpers/response.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Quaderno::Helpers + module Response + def response_body=(response) + @response_body = response + end + + def response_body + @response_body + end + end +end diff --git a/spec/fixtures/quaderno_cassettes/all_address_on_standard_account.yml b/spec/fixtures/quaderno_cassettes/all_address_on_standard_account.yml new file mode 100644 index 0000000..60c6afa --- /dev/null +++ b/spec/fixtures/quaderno_cassettes/all_address_on_standard_account.yml @@ -0,0 +1,63 @@ +--- +http_interactions: +- request: + method: get + uri: http://quaderno.lvh.me:3000/api/addresses.json + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Quaderno Ruby Gem 3.0.0 + Accept: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Authorization: + - Basic c2tfdGVzdF9iTXo5bUpKNWJabldQd1dHdVY4eTo= + response: + status: + code: 406 + message: Not Acceptable + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Ratelimit-Reset: + - '1689939315' + X-Ratelimit-Remaining: + - '99' + X-Ratelimit-Limit: + - '100' + Content-Type: + - application/json; charset=utf-8 + Vary: + - Origin + Cache-Control: + - no-cache + Content-Security-Policy: + - 'connect-src ''self'' https: http://localhost:3035 ws://localhost:3035' + X-Request-Id: + - 92cd3d60-d5f5-4df4-9f75-f90e2d644179 + X-Runtime: + - '0.040063' + Server-Timing: + - cache_write.active_support;dur=0.08, start_processing.action_controller;dur=0.04, + sql.active_record;dur=6.23, instantiation.active_record;dur=0.48, halted_callback.action_controller;dur=0.03, + process_action.action_controller;dur=12.33 + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '{"error":"Unsupported account type"}' + recorded_at: Fri, 21 Jul 2023 11:35:02 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/quaderno_cassettes/all_addresses_by_authentication_token.yml b/spec/fixtures/quaderno_cassettes/all_addresses_by_authentication_token.yml new file mode 100644 index 0000000..898e9dd --- /dev/null +++ b/spec/fixtures/quaderno_cassettes/all_addresses_by_authentication_token.yml @@ -0,0 +1,67 @@ +--- +http_interactions: +- request: + method: get + uri: http://quaderno.lvh.me:3000/api/addresses.json + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Quaderno Ruby Gem 3.0.0 + Accept: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Authorization: + - Basic c2tfdGVzdF9iTXo5bUpKNWJabldQd1dHdVY4eTo= + response: + status: + code: 200 + message: OK + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Ratelimit-Reset: + - '1689939315' + X-Ratelimit-Remaining: + - '99' + X-Ratelimit-Limit: + - '100' + Content-Type: + - application/json; charset=utf-8 + Vary: + - Origin + Etag: + - W/"a7f060d508742a53426c2c5f39bb545f" + Cache-Control: + - max-age=0, private, must-revalidate + Content-Security-Policy: + - 'connect-src ''self'' https: http://localhost:3035 ws://localhost:3035' + X-Request-Id: + - 95e73071-375a-4f63-b7f5-fe97c39df1a1 + X-Runtime: + - '0.047253' + Server-Timing: + - cache_write.active_support;dur=0.08, start_processing.action_controller;dur=0.07, + sql.active_record;dur=12.82, instantiation.active_record;dur=0.72, render_collection.action_view;dur=0.75, + render_template.action_view;dur=7.54, process_action.action_controller;dur=21.67 + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '[{"id":19,"country":"ES","street_line_1":null,"street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":34,"country":"ES","street_line_1":"Test","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":35,"country":"ES","street_line_1":"New + test address 2","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":36,"country":"ES","street_line_1":"Test 3","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":37,"country":"ES","street_line_1":"Test_Address + 2 line 1","street_line_2":"Test_Address 2 line 2","city":"TCity","postal_code":"1234","region":null,"valid_from":"2023-01-01","valid_until":null}]' + recorded_at: Fri, 21 Jul 2023 11:35:12 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/quaderno_cassettes/found_address_by_access_token.yml b/spec/fixtures/quaderno_cassettes/found_address_by_access_token.yml new file mode 100644 index 0000000..123575d --- /dev/null +++ b/spec/fixtures/quaderno_cassettes/found_address_by_access_token.yml @@ -0,0 +1,129 @@ +--- +http_interactions: +- request: + method: get + uri: http://quaderno.lvh.me:3000/api/addresses.json + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Quaderno Ruby Gem 3.0.0 + Accept: + - application/json + Authorization: + - Bearer afa16c7478f0ba3be222e627c2571d4dd5dca47924996b13a3af377feca47ff0 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Ratelimit-Reset: + - '1689939495' + X-Ratelimit-Remaining: + - '99' + X-Ratelimit-Limit: + - '100' + Content-Type: + - application/json; charset=utf-8 + Vary: + - Origin + Etag: + - W/"a7f060d508742a53426c2c5f39bb545f" + Cache-Control: + - max-age=0, private, must-revalidate + Content-Security-Policy: + - 'connect-src ''self'' https: http://localhost:3035 ws://localhost:3035' + X-Request-Id: + - 8f731a9d-9fd4-497d-8aff-04e295251fd3 + X-Runtime: + - '0.071523' + Server-Timing: + - cache_write.active_support;dur=0.05, start_processing.action_controller;dur=0.04, + sql.active_record;dur=22.66, instantiation.active_record;dur=2.70, render_collection.action_view;dur=0.87, + render_template.action_view;dur=2.63, process_action.action_controller;dur=38.41 + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '[{"id":19,"country":"ES","street_line_1":null,"street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":34,"country":"ES","street_line_1":"Test","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":35,"country":"ES","street_line_1":"New + test address 2","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":36,"country":"ES","street_line_1":"Test 3","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":37,"country":"ES","street_line_1":"Test_Address + 2 line 1","street_line_2":"Test_Address 2 line 2","city":"TCity","postal_code":"1234","region":null,"valid_from":"2023-01-01","valid_until":null}]' + recorded_at: Fri, 21 Jul 2023 11:38:10 GMT +- request: + method: get + uri: http://quaderno.lvh.me:3000/api/addresses/35.json + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Quaderno Ruby Gem 3.0.0 + Accept: + - application/json + Authorization: + - Bearer afa16c7478f0ba3be222e627c2571d4dd5dca47924996b13a3af377feca47ff0 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Ratelimit-Reset: + - '1689939495' + X-Ratelimit-Remaining: + - '99' + X-Ratelimit-Limit: + - '100' + Content-Type: + - application/json; charset=utf-8 + Vary: + - Origin + Etag: + - W/"9502c29c4c82b3f5493a69ccc2bfb40c" + Cache-Control: + - max-age=0, private, must-revalidate + Content-Security-Policy: + - 'connect-src ''self'' https: http://localhost:3035 ws://localhost:3035' + X-Request-Id: + - 196cb0dd-407f-4673-95a4-f3774f49dcc5 + X-Runtime: + - '0.025474' + Server-Timing: + - cache_write.active_support;dur=0.05, start_processing.action_controller;dur=0.06, + sql.active_record;dur=3.71, instantiation.active_record;dur=0.50, render_partial.action_view;dur=0.18, + render_template.action_view;dur=0.29, process_action.action_controller;dur=8.81 + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '{"id":35,"country":"ES","street_line_1":"New test address 2","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null}' + recorded_at: Fri, 21 Jul 2023 11:38:10 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/quaderno_cassettes/found_address_by_authentication_token.yml b/spec/fixtures/quaderno_cassettes/found_address_by_authentication_token.yml new file mode 100644 index 0000000..5db05bc --- /dev/null +++ b/spec/fixtures/quaderno_cassettes/found_address_by_authentication_token.yml @@ -0,0 +1,128 @@ +--- +http_interactions: +- request: + method: get + uri: http://quaderno.lvh.me:3000/api/addresses.json + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Quaderno Ruby Gem 3.0.0 + Accept: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Authorization: + - Basic c2tfdGVzdF9iTXo5bUpKNWJabldQd1dHdVY4eTo= + response: + status: + code: 200 + message: OK + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Ratelimit-Reset: + - '1689939270' + X-Ratelimit-Remaining: + - '99' + X-Ratelimit-Limit: + - '100' + Content-Type: + - application/json; charset=utf-8 + Vary: + - Origin + Etag: + - W/"9d0c982d09c953428a094c63a52f4eee" + Cache-Control: + - max-age=0, private, must-revalidate + Content-Security-Policy: + - 'connect-src ''self'' https: http://localhost:3035 ws://localhost:3035' + X-Request-Id: + - 4c68632a-4cb4-4707-884e-f9784f829bdc + X-Runtime: + - '0.107005' + Server-Timing: + - cache_write.active_support;dur=0.15, start_processing.action_controller;dur=0.08, + sql.active_record;dur=18.48, instantiation.active_record;dur=5.06, render_collection.action_view;dur=0.97, + render_template.action_view;dur=3.58, process_action.action_controller;dur=68.55 + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '[{"id":19,"country":"ES","street_line_1":null,"street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":34,"country":"ES","street_line_1":"Test","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":35,"country":"ES","street_line_1":"Test + 2","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":36,"country":"ES","street_line_1":"Test 3","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null}]' + recorded_at: Fri, 21 Jul 2023 11:34:15 GMT +- request: + method: get + uri: http://quaderno.lvh.me:3000/api/addresses/35.json + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Quaderno Ruby Gem 3.0.0 + Accept: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Authorization: + - Basic c2tfdGVzdF9iTXo5bUpKNWJabldQd1dHdVY4eTo= + response: + status: + code: 200 + message: OK + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Ratelimit-Reset: + - '1689939270' + X-Ratelimit-Remaining: + - '99' + X-Ratelimit-Limit: + - '100' + Content-Type: + - application/json; charset=utf-8 + Vary: + - Origin + Etag: + - W/"95c1b6b38d6d586f504944a088cd6ed2" + Cache-Control: + - max-age=0, private, must-revalidate + Content-Security-Policy: + - 'connect-src ''self'' https: http://localhost:3035 ws://localhost:3035' + X-Request-Id: + - c039c2dc-9790-4863-8953-99198af5d8ae + X-Runtime: + - '0.035061' + Server-Timing: + - cache_write.active_support;dur=0.05, start_processing.action_controller;dur=0.05, + sql.active_record;dur=10.79, instantiation.active_record;dur=0.55, render_partial.action_view;dur=0.42, + render_template.action_view;dur=0.78, process_action.action_controller;dur=17.80 + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '{"id":35,"country":"ES","street_line_1":"Test 2","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null}' + recorded_at: Fri, 21 Jul 2023 11:34:15 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/quaderno_cassettes/new_address_by_access_token.yml b/spec/fixtures/quaderno_cassettes/new_address_by_access_token.yml new file mode 100644 index 0000000..cd14d2c --- /dev/null +++ b/spec/fixtures/quaderno_cassettes/new_address_by_access_token.yml @@ -0,0 +1,70 @@ +--- +http_interactions: +- request: + method: post + uri: http://quaderno.lvh.me:3000/api/addresses.json + body: + encoding: UTF-8 + string: '{"street_line_1":"Test_Address 1 line 1","street_line_2":"Test_Address + 1 line 2","postal_code":"1234","city":"TCity"}' + headers: + User-Agent: + - Quaderno Ruby Gem 3.0.0 + Accept: + - application/json + Authorization: + - Bearer afa16c7478f0ba3be222e627c2571d4dd5dca47924996b13a3af377feca47ff0 + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 201 + message: Created + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Ratelimit-Reset: + - '1689939495' + X-Ratelimit-Remaining: + - '99' + X-Ratelimit-Limit: + - '100' + Content-Type: + - application/json; charset=utf-8 + Vary: + - Origin + Etag: + - W/"e848fec9e8710bab0da9a73bc4a200e1" + Cache-Control: + - max-age=0, private, must-revalidate + Content-Security-Policy: + - 'connect-src ''self'' https: http://localhost:3035 ws://localhost:3035' + X-Request-Id: + - 74eca40e-aa6f-4508-8224-722b61604bdb + X-Runtime: + - '0.065794' + Server-Timing: + - cache_write.active_support;dur=0.05, start_processing.action_controller;dur=0.05, + sql.active_record;dur=39.06, instantiation.active_record;dur=0.55, unpermitted_parameters.action_controller;dur=0.05, + render_partial.action_view;dur=0.09, render_template.action_view;dur=0.18, + process_action.action_controller;dur=48.71 + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '{"id":38,"country":"ES","street_line_1":"Test_Address 1 line 1","street_line_2":"Test_Address + 1 line 2","city":"TCity","postal_code":"1234","region":null,"valid_from":"2023-01-01","valid_until":null}' + recorded_at: Fri, 21 Jul 2023 11:38:10 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/quaderno_cassettes/new_address_by_authentication_token.yml b/spec/fixtures/quaderno_cassettes/new_address_by_authentication_token.yml new file mode 100644 index 0000000..8dbf1d2 --- /dev/null +++ b/spec/fixtures/quaderno_cassettes/new_address_by_authentication_token.yml @@ -0,0 +1,70 @@ +--- +http_interactions: +- request: + method: post + uri: http://quaderno.lvh.me:3000/api/addresses.json + body: + encoding: UTF-8 + string: '{"street_line_1":"Test_Address 2 line 1","street_line_2":"Test_Address + 2 line 2","postal_code":"1234","city":"TCity"}' + headers: + User-Agent: + - Quaderno Ruby Gem 3.0.0 + Accept: + - application/json + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Authorization: + - Basic c2tfdGVzdF9iTXo5bUpKNWJabldQd1dHdVY4eTo= + response: + status: + code: 201 + message: Created + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Ratelimit-Reset: + - '1689939270' + X-Ratelimit-Remaining: + - '99' + X-Ratelimit-Limit: + - '100' + Content-Type: + - application/json; charset=utf-8 + Vary: + - Origin + Etag: + - W/"f0c0966e5e7bb426ba4747a294ff3151" + Cache-Control: + - max-age=0, private, must-revalidate + Content-Security-Policy: + - 'connect-src ''self'' https: http://localhost:3035 ws://localhost:3035' + X-Request-Id: + - 752de1be-57c2-4c93-9219-d484261b5f45 + X-Runtime: + - '0.035952' + Server-Timing: + - cache_write.active_support;dur=0.07, start_processing.action_controller;dur=0.06, + sql.active_record;dur=10.40, instantiation.active_record;dur=0.44, unpermitted_parameters.action_controller;dur=0.06, + render_partial.action_view;dur=0.09, render_template.action_view;dur=0.41, + process_action.action_controller;dur=18.88 + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '{"id":37,"country":"ES","street_line_1":"Test_Address 2 line 1","street_line_2":"Test_Address + 2 line 2","city":"TCity","postal_code":"1234","region":null,"valid_from":"2023-01-01","valid_until":null}' + recorded_at: Fri, 21 Jul 2023 11:34:15 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/quaderno_cassettes/updated_address_by_access_token.yml b/spec/fixtures/quaderno_cassettes/updated_address_by_access_token.yml new file mode 100644 index 0000000..b882627 --- /dev/null +++ b/spec/fixtures/quaderno_cassettes/updated_address_by_access_token.yml @@ -0,0 +1,133 @@ +--- +http_interactions: +- request: + method: get + uri: http://quaderno.lvh.me:3000/api/addresses.json + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Quaderno Ruby Gem 3.0.0 + Accept: + - application/json + Authorization: + - Bearer afa16c7478f0ba3be222e627c2571d4dd5dca47924996b13a3af377feca47ff0 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Ratelimit-Reset: + - '1689939495' + X-Ratelimit-Remaining: + - '99' + X-Ratelimit-Limit: + - '100' + Content-Type: + - application/json; charset=utf-8 + Vary: + - Origin + Etag: + - W/"7b50679b76a3ba7be276bb7415c291a4" + Cache-Control: + - max-age=0, private, must-revalidate + Content-Security-Policy: + - 'connect-src ''self'' https: http://localhost:3035 ws://localhost:3035' + X-Request-Id: + - 17c721e9-c0d2-4ffb-93a5-ab1387ace310 + X-Runtime: + - '0.028587' + Server-Timing: + - cache_write.active_support;dur=0.04, start_processing.action_controller;dur=0.04, + sql.active_record;dur=3.65, instantiation.active_record;dur=0.63, render_collection.action_view;dur=0.80, + render_template.action_view;dur=2.44, process_action.action_controller;dur=10.53 + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '[{"id":19,"country":"ES","street_line_1":null,"street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":34,"country":"ES","street_line_1":"Test","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":35,"country":"ES","street_line_1":"New + test address 2","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":36,"country":"ES","street_line_1":"Test 3","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":37,"country":"ES","street_line_1":"Test_Address + 2 line 1","street_line_2":"Test_Address 2 line 2","city":"TCity","postal_code":"1234","region":null,"valid_from":"2023-01-01","valid_until":null},{"id":38,"country":"ES","street_line_1":"Test_Address + 1 line 1","street_line_2":"Test_Address 1 line 2","city":"TCity","postal_code":"1234","region":null,"valid_from":"2023-01-01","valid_until":null}]' + recorded_at: Fri, 21 Jul 2023 11:38:10 GMT +- request: + method: put + uri: http://quaderno.lvh.me:3000/api/addresses/35.json + body: + encoding: UTF-8 + string: '{"street_line_1":"New test address 1"}' + headers: + User-Agent: + - Quaderno Ruby Gem 3.0.0 + Accept: + - application/json + Authorization: + - Bearer afa16c7478f0ba3be222e627c2571d4dd5dca47924996b13a3af377feca47ff0 + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Ratelimit-Reset: + - '1689939495' + X-Ratelimit-Remaining: + - '99' + X-Ratelimit-Limit: + - '100' + Content-Type: + - application/json; charset=utf-8 + Vary: + - Origin + Etag: + - W/"b4fb31f46fb6f945780ebc2814890392" + Cache-Control: + - max-age=0, private, must-revalidate + Content-Security-Policy: + - 'connect-src ''self'' https: http://localhost:3035 ws://localhost:3035' + X-Request-Id: + - ec0e3d3f-f2dd-40d1-9a62-fb32a6e7c523 + X-Runtime: + - '0.032510' + Server-Timing: + - cache_write.active_support;dur=0.07, start_processing.action_controller;dur=0.05, + sql.active_record;dur=7.73, instantiation.active_record;dur=0.49, unpermitted_parameters.action_controller;dur=0.06, + render_partial.action_view;dur=0.09, render_template.action_view;dur=0.15, + process_action.action_controller;dur=13.68 + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '{"id":35,"country":"ES","street_line_1":"New test address 1","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null}' + recorded_at: Fri, 21 Jul 2023 11:38:10 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/fixtures/quaderno_cassettes/updated_address_by_authentication_token.yml b/spec/fixtures/quaderno_cassettes/updated_address_by_authentication_token.yml new file mode 100644 index 0000000..43496a5 --- /dev/null +++ b/spec/fixtures/quaderno_cassettes/updated_address_by_authentication_token.yml @@ -0,0 +1,132 @@ +--- +http_interactions: +- request: + method: get + uri: http://quaderno.lvh.me:3000/api/addresses.json + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Quaderno Ruby Gem 3.0.0 + Accept: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Authorization: + - Basic c2tfdGVzdF9iTXo5bUpKNWJabldQd1dHdVY4eTo= + response: + status: + code: 200 + message: OK + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Ratelimit-Reset: + - '1689939270' + X-Ratelimit-Remaining: + - '99' + X-Ratelimit-Limit: + - '100' + Content-Type: + - application/json; charset=utf-8 + Vary: + - Origin + Etag: + - W/"75330565952f24138f43b1cb54f82635" + Cache-Control: + - max-age=0, private, must-revalidate + Content-Security-Policy: + - 'connect-src ''self'' https: http://localhost:3035 ws://localhost:3035' + X-Request-Id: + - f9f665b8-8714-42a6-bcdc-9c7314519741 + X-Runtime: + - '0.040517' + Server-Timing: + - cache_write.active_support;dur=0.05, start_processing.action_controller;dur=0.04, + sql.active_record;dur=15.43, instantiation.active_record;dur=0.68, render_collection.action_view;dur=0.94, + render_template.action_view;dur=2.67, process_action.action_controller;dur=23.82 + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '[{"id":19,"country":"ES","street_line_1":null,"street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":34,"country":"ES","street_line_1":"Test","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":35,"country":"ES","street_line_1":"Test + 2","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":36,"country":"ES","street_line_1":"Test 3","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null},{"id":37,"country":"ES","street_line_1":"Test_Address + 2 line 1","street_line_2":"Test_Address 2 line 2","city":"TCity","postal_code":"1234","region":null,"valid_from":"2023-01-01","valid_until":null}]' + recorded_at: Fri, 21 Jul 2023 11:34:15 GMT +- request: + method: put + uri: http://quaderno.lvh.me:3000/api/addresses/35.json + body: + encoding: UTF-8 + string: '{"street_line_1":"New test address 2"}' + headers: + User-Agent: + - Quaderno Ruby Gem 3.0.0 + Accept: + - application/json + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Authorization: + - Basic c2tfdGVzdF9iTXo5bUpKNWJabldQd1dHdVY4eTo= + response: + status: + code: 200 + message: OK + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Ratelimit-Reset: + - '1689939270' + X-Ratelimit-Remaining: + - '99' + X-Ratelimit-Limit: + - '100' + Content-Type: + - application/json; charset=utf-8 + Vary: + - Origin + Etag: + - W/"9502c29c4c82b3f5493a69ccc2bfb40c" + Cache-Control: + - max-age=0, private, must-revalidate + Content-Security-Policy: + - 'connect-src ''self'' https: http://localhost:3035 ws://localhost:3035' + X-Request-Id: + - 53ad13b5-74e5-4d42-a193-0bd05c117038 + X-Runtime: + - '0.037118' + Server-Timing: + - cache_write.active_support;dur=0.08, start_processing.action_controller;dur=0.05, + sql.active_record;dur=11.23, instantiation.active_record;dur=0.55, unpermitted_parameters.action_controller;dur=0.03, + render_partial.action_view;dur=0.09, render_template.action_view;dur=0.44, + process_action.action_controller;dur=19.15 + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '{"id":35,"country":"ES","street_line_1":"New test address 2","street_line_2":null,"city":null,"postal_code":null,"region":null,"valid_from":"2023-01-01","valid_until":null}' + recorded_at: Fri, 21 Jul 2023 11:34:15 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/unit/test_quaderno_addresses.rb b/spec/unit/test_quaderno_addresses.rb new file mode 100644 index 0000000..682a93c --- /dev/null +++ b/spec/unit/test_quaderno_addresses.rb @@ -0,0 +1,103 @@ +# frozen_string_literal: true + +require 'helper' + +describe Quaderno::Address do + context 'when accessing a standard account' do + before do + Quaderno::Base.configure do |config| + config.auth_token = TEST_KEY + config.url = TEST_URL + config.api_version = nil + end + end + + it 'should get an error' do + VCR.use_cassette('all address on standard account') do + expect { Quaderno::Address.all }.to raise_error(Quaderno::Exceptions::InvalidRequest) + end + end + end + + context 'when accessing a custom account' do + context 'using the thread-safe configuration' do + context 'with an authentication token' do + it 'should get all addresses (populated db)' do + VCR.use_cassette('all addresses by authentication token') do + addresses = Quaderno::Address.all(api_url: TEST_URL, access_token: TEST_OAUTH_ACCESS_TOKEN) + expect(addresses.is_a?(Array)).to be true + addresses.each { |address| expect(address.is_a?(Quaderno::Address)).to be true } + end + end + + it 'should find an address' do + VCR.use_cassette('found address by authentication token') do + addresses = Quaderno::Address.all(api_url: TEST_URL, auth_token: TEST_KEY) + address = Quaderno::Address.find addresses[2].id, api_url: TEST_URL, auth_token: TEST_KEY + expect(address.is_a?(Quaderno::Address)).to be true + expect(addresses[2].id).to eq address.id + end + end + + it 'should create an address' do + VCR.use_cassette('new address by authentication token') do + address = Quaderno::Address.create(street_line_1: 'Test_Address 2 line 1', street_line_2: 'Test_Address 2 line 2', postal_code: '1234', city: 'TCity', api_url: TEST_URL, access_token: TEST_OAUTH_ACCESS_TOKEN) + expect(address.is_a?(Quaderno::Address)).to be true + expect(address.street_line_1).to eq 'Test_Address 2 line 1' + expect(address.street_line_2).to eq 'Test_Address 2 line 2' + expect(address.postal_code).to eq '1234' + expect(address.city).to eq 'TCity' + end + end + + it 'should update an address' do + VCR.use_cassette('updated address by authentication token') do + addresses = Quaderno::Address.all(api_url: TEST_URL, auth_token: TEST_KEY) + address = Quaderno::Address.update(addresses[2].id, street_line_1: 'New test address 2', api_url: TEST_URL, access_token: TEST_OAUTH_ACCESS_TOKEN) + expect(address.is_a?(Quaderno::Address)).to be true + expect(address.street_line_1).to eq 'New test address 2' + end + end + end + + context 'with an OAuth 2.0 access token' do + it 'should get all addresses (populated db)' do + VCR.use_cassette('all addresses by authentication token') do + addresses = Quaderno::Address.all(api_url: TEST_URL, access_token: TEST_OAUTH_ACCESS_TOKEN) + expect(addresses.is_a?(Array)).to be true + addresses.each { |address| expect(address.is_a?(Quaderno::Address)).to be true } + end + end + + it 'should find an address' do + VCR.use_cassette('found address by access token') do + addresses = Quaderno::Address.all(api_url: TEST_URL, access_token: TEST_OAUTH_ACCESS_TOKEN) + address = Quaderno::Address.find addresses[2].id, api_url: TEST_URL, access_token: TEST_OAUTH_ACCESS_TOKEN + expect(address.is_a?(Quaderno::Address)).to be true + expect(addresses[2].id).to eq address.id + end + end + + it 'should create an address' do + VCR.use_cassette('new address by access token') do + address = Quaderno::Address.create(street_line_1: 'Test_Address 1 line 1', street_line_2: 'Test_Address 1 line 2', postal_code: '1234', city: 'TCity', api_url: TEST_URL, access_token: TEST_OAUTH_ACCESS_TOKEN) + expect(address.is_a?(Quaderno::Address)).to be true + expect(address.street_line_1).to eq 'Test_Address 1 line 1' + expect(address.street_line_2).to eq 'Test_Address 1 line 2' + expect(address.postal_code).to eq '1234' + expect(address.city).to eq 'TCity' + end + end + + it 'should update an address' do + VCR.use_cassette('updated address by access token') do + addresses = Quaderno::Address.all(api_url: TEST_URL, access_token: TEST_OAUTH_ACCESS_TOKEN) + address = Quaderno::Address.update(addresses[2].id, street_line_1: 'New test address 1', api_url: TEST_URL, access_token: TEST_OAUTH_ACCESS_TOKEN) + expect(address.is_a?(Quaderno::Address)).to be true + expect(address.street_line_1).to eq 'New test address 1' + end + end + end + end + end +end