diff --git a/spec/lib/convenient_service/examples/standard/request_params/services/prepare_spec.rb b/spec/lib/convenient_service/examples/standard/request_params/services/prepare_spec.rb index d6f98d7d121..2847d9f784a 100644 --- a/spec/lib/convenient_service/examples/standard/request_params/services/prepare_spec.rb +++ b/spec/lib/convenient_service/examples/standard/request_params/services/prepare_spec.rb @@ -6,11 +6,11 @@ # rubocop:disable RSpec/NestedGroups, RSpec/MultipleMemoizedHelpers RSpec.describe ConvenientService::Examples::Standard::RequestParams::Services::Prepare do + include ConvenientService::RSpec::Matchers::DelegateTo + include ConvenientService::RSpec::Matchers::Results + example_group "class methods" do describe ".result" do - include ConvenientService::RSpec::Matchers::DelegateTo - include ConvenientService::RSpec::Matchers::Results - subject(:result) { described_class.result(request: request) } let(:request) { ConvenientService::Examples::Standard::RequestParams::Entities::Request.new(http_string: http_string) } @@ -49,13 +49,9 @@ end let(:path) { "/rules/%{id}.%{format}" % path_params } - let(:path_params) { {id: id, format: format} } - let(:id) { "1000000" } - let(:format) { "json" } - let(:body) { JSON.generate(json_body) } let(:json_body) do @@ -69,13 +65,9 @@ end let(:body_params) { json_body.transform_keys(&:to_sym) } - let(:merged_params) { path_params.merge(body_params) } - let(:permitted_params) { merged_params.slice(*(merged_params.keys - [:verified])) } - let(:params_with_defaults) { defaults.merge(permitted_params) } - let(:original_params) { params_with_defaults } let(:casted_params) do @@ -96,100 +88,84 @@ allow(ConvenientService::Examples::Standard::RequestParams::Entities::Logger).to receive(:log).with(anything) end - context "when request is NOT valid to extract params from path" do - ## - # Contains invalid path. - # https://www.w3.org/TR/2011/WD-html5-20110525/urls.html - # - let(:path) { "/ru*les/1.json" } - let(:pattern) { /^\/rules\/(?\d+)\.(?\w+)$/ } + context "when `Prepare` is NOT successful" do + context "when `ExtractParamsFromPath` is NOT successful" do + ## + # Contains invalid path. + # https://www.w3.org/TR/2011/WD-html5-20110525/urls.html + # + let(:path) { "/ru*les/1.json" } + let(:pattern) { /^\/rules\/(?\d+)\.(?\w+)$/ } - it "fails to extract params from path" do - expect(result).to be_error.of_step(ConvenientService::Examples::Standard::RequestParams::Services::ExtractParamsFromPath) + it "returns intermediate step result" do + expect(result).to be_not_success.of_step(ConvenientService::Examples::Standard::RequestParams::Services::ExtractParamsFromPath) + end end - end - context "when request is NOT valid to extract params from body" do - ## - # Contains unparsable JSON body. - # - let(:body) { "abc" } + context "when `ExtractParamsFromBody` is NOT successful" do + ## + # Contains unparsable JSON body. + # + let(:body) { "abc" } - it "fails to extract params from body" do - expect(result).to be_error.of_step(ConvenientService::Examples::Standard::RequestParams::Services::ExtractParamsFromBody) + it "returns intermediate step result" do + expect(result).to be_not_success.of_step(ConvenientService::Examples::Standard::RequestParams::Services::ExtractParamsFromBody) + end end - end - context "when request is valid to extract params from both path and body" do - it "merges params extracted from path and body" do + context "when uncasted params are NOT valid" do ## - # TODO: Introduce `delegate_to_service` to hide `commit_config!`. + # Contains unsupported format, only JSON is available. # - ConvenientService::Examples::Standard::RequestParams::Services::MergeParams.commit_config! + let(:path) { "/rules/1.html" } + + it "returns intermediate step result" do + expect(result).to be_not_success.of_step(ConvenientService::Examples::Standard::RequestParams::Services::ValidateUncastedParams) + end + end + + context "when casted params are NOT valid" do + before do + allow(ConvenientService::Examples::Standard::RequestParams::Entities::ID).to receive(:cast).and_return(nil) + end + it "returns intermediate step result" do + expect(result).to be_not_success.of_step(ConvenientService::Examples::Standard::RequestParams::Services::ValidateCastedParams) + end + end + end + + context "when `Prepare` is successful" do + specify do expect { result } .to delegate_to(ConvenientService::Examples::Standard::RequestParams::Services::MergeParams, :result) .with_arguments(params_from_path: path_params, params_from_body: body_params) end - it "logs merged params from path and body with \"Uncasted\" tag" do - ## - # TODO: Introduce `delegate_to_service` to hide `commit_config!`. - # - ConvenientService::Examples::Standard::RequestParams::Services::LogRequestParams.commit_config! - + specify do expect { result } .to delegate_to(ConvenientService::Examples::Standard::RequestParams::Services::LogRequestParams, :result) .with_arguments(request: request, params: merged_params, tag: "Uncasted") end - it "filters out unpermitted keys" do - ConvenientService::Examples::Standard::RequestParams::Services::FilterOutUnpermittedParams.commit_config! - + specify do expect { result } .to delegate_to(ConvenientService::Examples::Standard::RequestParams::Services::FilterOutUnpermittedParams, :result) .with_arguments(params: merged_params, permitted_keys: permitted_keys) end - it "applies default values" do - ConvenientService::Examples::Standard::RequestParams::Services::ApplyDefaultParamValues.commit_config! - + specify do expect { result } .to delegate_to(ConvenientService::Examples::Standard::RequestParams::Services::ApplyDefaultParamValues, :result) .with_arguments(params: permitted_params, defaults: defaults) end - end - - context "when uncasted params are NOT valid" do - ## - # Contains unsupported format, only JSON is available. - # - let(:path) { "/rules/1.html" } - it "fails to validate uncasted params" do - expect(result).to be_error.of_step(ConvenientService::Examples::Standard::RequestParams::Services::ValidateUncastedParams) - end - end - - context "when uncasted params are valid" do - it "logs casted params with \"Casted\" tag" do + specify do expect { result } .to delegate_to(ConvenientService::Examples::Standard::RequestParams::Services::LogRequestParams, :result) .with_arguments(request: request, params: casted_params, tag: "Casted") end - end - - context "when casted params are NOT valid" do - before do - allow(ConvenientService::Examples::Standard::RequestParams::Entities::ID).to receive(:cast).and_return(nil) - end - - it "fails to validate casted params" do - expect(result).to be_error.of_step(ConvenientService::Examples::Standard::RequestParams::Services::ValidateCastedParams) - end - end - context "when casted params are valid" do it "returns `success` with casted params" do expect(result).to be_success.with_data(params: casted_params) end diff --git a/spec/lib/convenient_service/examples/standard/v1/request_params/services/apply_default_param_values_spec.rb b/spec/lib/convenient_service/examples/standard/v1/request_params/services/apply_default_param_values_spec.rb index 27970b8f30e..31f2fe908df 100644 --- a/spec/lib/convenient_service/examples/standard/v1/request_params/services/apply_default_param_values_spec.rb +++ b/spec/lib/convenient_service/examples/standard/v1/request_params/services/apply_default_param_values_spec.rb @@ -6,24 +6,26 @@ # rubocop:disable RSpec/NestedGroups RSpec.describe ConvenientService::Examples::Standard::V1::RequestParams::Services::ApplyDefaultParamValues do + include ConvenientService::RSpec::Matchers::Results + example_group "class methods" do describe ".result" do - include ConvenientService::RSpec::Matchers::Results - - subject(:result) { described_class.result(params: params, defaults: defaults) } + context "when `ApplyDefaultParamValues` is successful" do + subject(:result) { described_class.result(params: params, defaults: defaults) } - let(:params) { {id: "1000000", title: "Check the official User Docs"} } - let(:defaults) { {tags: [], sources: []} } + let(:params) { {id: "1000000", title: "Check the official User Docs"} } + let(:defaults) { {tags: [], sources: []} } - it "returns success with params and defaults" do - expect(result).to be_success.with_data(params: {id: "1000000", title: "Check the official User Docs", tags: [], sources: []}) - end + it "returns `success` with params and defaults" do + expect(result).to be_success.with_data(params: {id: "1000000", title: "Check the official User Docs", tags: [], sources: []}) + end - context "when `params` and `defaults` have same keys" do - let(:params) { {id: "1000000", title: "Check the official User Docs", tags: ["ruby"]} } + context "when `params` and `defaults` have same keys" do + let(:params) { {id: "1000000", title: "Check the official User Docs", tags: ["ruby"]} } - it "takes value from `params`" do - expect(result).to be_success.with_data(params: {id: "1000000", title: "Check the official User Docs", tags: ["ruby"], sources: []}) + it "takes value from `params`" do + expect(result).to be_success.with_data(params: {id: "1000000", title: "Check the official User Docs", tags: ["ruby"], sources: []}) + end end end end diff --git a/spec/lib/convenient_service/examples/standard/v1/request_params/services/cast_params_spec.rb b/spec/lib/convenient_service/examples/standard/v1/request_params/services/cast_params_spec.rb index eb02f1e53bc..81ddb602aac 100644 --- a/spec/lib/convenient_service/examples/standard/v1/request_params/services/cast_params_spec.rb +++ b/spec/lib/convenient_service/examples/standard/v1/request_params/services/cast_params_spec.rb @@ -6,36 +6,38 @@ # rubocop:disable RSpec/NestedGroups RSpec.describe ConvenientService::Examples::Standard::V1::RequestParams::Services::CastParams do + include ConvenientService::RSpec::Matchers::Results + example_group "class methods" do describe ".result" do - include ConvenientService::RSpec::Matchers::Results - - subject(:result) { described_class.result(params: original_params) } + context "when `CastParams` is successful" do + subject(:result) { described_class.result(params: original_params) } - let(:original_params) do - { - id: "1000000", - format: "html", - title: "Avoid error shadowing", - description: "Check the official User Docs", - tags: "ruby", - sources: "https://www.rubyguides.com/2019/07/ruby-instance-variables/" - } - end + let(:original_params) do + { + id: "1000000", + format: "html", + title: "Avoid error shadowing", + description: "Check the official User Docs", + tags: "ruby", + sources: "https://www.rubyguides.com/2019/07/ruby-instance-variables/" + } + end - let(:casted_params) do - { - id: ConvenientService::Examples::Standard::V1::RequestParams::Entities::ID.cast(original_params[:id]), - format: ConvenientService::Examples::Standard::V1::RequestParams::Entities::Format.cast(original_params[:format]), - title: ConvenientService::Examples::Standard::V1::RequestParams::Entities::Title.cast(original_params[:title]), - description: ConvenientService::Examples::Standard::V1::RequestParams::Entities::Description.cast(original_params[:description]), - tags: [ConvenientService::Examples::Standard::V1::RequestParams::Entities::Tag.cast(original_params[:tags])], - sources: [ConvenientService::Examples::Standard::V1::RequestParams::Entities::Source.cast(original_params[:sources])] - } - end + let(:casted_params) do + { + id: ConvenientService::Examples::Standard::V1::RequestParams::Entities::ID.cast(original_params[:id]), + format: ConvenientService::Examples::Standard::V1::RequestParams::Entities::Format.cast(original_params[:format]), + title: ConvenientService::Examples::Standard::V1::RequestParams::Entities::Title.cast(original_params[:title]), + description: ConvenientService::Examples::Standard::V1::RequestParams::Entities::Description.cast(original_params[:description]), + tags: [ConvenientService::Examples::Standard::V1::RequestParams::Entities::Tag.cast(original_params[:tags])], + sources: [ConvenientService::Examples::Standard::V1::RequestParams::Entities::Source.cast(original_params[:sources])] + } + end - it "returns success with original and casted params" do - expect(result).to be_success.with_data(original_params: original_params, casted_params: casted_params) + it "returns `success` with original and casted params" do + expect(result).to be_success.with_data(original_params: original_params, casted_params: casted_params) + end end end end diff --git a/spec/lib/convenient_service/examples/standard/v1/request_params/services/extract_params_from_body_spec.rb b/spec/lib/convenient_service/examples/standard/v1/request_params/services/extract_params_from_body_spec.rb index 71a4111c81e..9709a92efb5 100644 --- a/spec/lib/convenient_service/examples/standard/v1/request_params/services/extract_params_from_body_spec.rb +++ b/spec/lib/convenient_service/examples/standard/v1/request_params/services/extract_params_from_body_spec.rb @@ -6,80 +6,82 @@ # rubocop:disable RSpec/NestedGroups RSpec.describe ConvenientService::Examples::Standard::V1::RequestParams::Services::ExtractParamsFromBody do + include ConvenientService::RSpec::Matchers::Results + example_group "class methods" do describe ".result" do - include ConvenientService::RSpec::Matchers::Results - subject(:result) { described_class.result(request: request) } let(:request) { ConvenientService::Examples::Standard::V1::RequestParams::Entities::Request.new(http_string: http_string) } - context "when request is NOT valid for HTTP parsing" do - let(:http_string) do - <<~TEXT - POST /rules/1000000.json HTTP/1.1 - User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 - Host: code-review.com - Content-Type: application/json; charset=utf-8 - Content-Length: 105 - Accept-Language: en-us - {"title":"Avoid error shadowing","description":"Check the official User Docs","tags":["error-shadowing"]} - Accept-Encoding: gzip, deflate - Connection: Keep-Alive - TEXT - end - - let(:error_message) do - <<~MESSAGE - Failed to resolve body since request is NOT HTTP parsable. - - Request: - --- - #{request} - --- - MESSAGE - end - - it "fails to parse request body" do - expect(result).to be_error.with_message(error_message) - end - end - - context "when request body is NOT valid for JSON parsing" do - let(:http_string) do - <<~TEXT - POST /rules/1000000.json HTTP/1.1 - User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 - Host: code-review.com - Content-Type: application/json; charset=utf-8 - Content-Length: #{body.length} - Accept-Language: en-us - Accept-Encoding: gzip, deflate - Connection: Keep-Alive - - #{body} - TEXT - end - - let(:body) { "abc" } - - let(:error_message) do - <<~MESSAGE - Request body contains invalid json. - - Request: - --- - #{request} - --- - MESSAGE + context "when `ExtractParamsFromBody` is NOT successful" do + context "when request is NOT valid for HTTP parsing" do + let(:http_string) do + <<~TEXT + POST /rules/1000000.json HTTP/1.1 + User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 + Host: code-review.com + Content-Type: application/json; charset=utf-8 + Content-Length: 105 + Accept-Language: en-us + {"title":"Avoid error shadowing","description":"Check the official User Docs","tags":["error-shadowing"]} + Accept-Encoding: gzip, deflate + Connection: Keep-Alive + TEXT + end + + let(:error_message) do + <<~MESSAGE + Failed to resolve body since request is NOT HTTP parsable. + + Request: + --- + #{request} + --- + MESSAGE + end + + it "returns `error` with message" do + expect(result).to be_error.with_message(error_message) + end end - it "fails to parse JSON from request body" do - expect(result).to be_error.with_message(error_message) + context "when request body is NOT valid for JSON parsing" do + let(:http_string) do + <<~TEXT + POST /rules/1000000.json HTTP/1.1 + User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 + Host: code-review.com + Content-Type: application/json; charset=utf-8 + Content-Length: #{body.length} + Accept-Language: en-us + Accept-Encoding: gzip, deflate + Connection: Keep-Alive + + #{body} + TEXT + end + + let(:body) { "abc" } + + let(:error_message) do + <<~MESSAGE + Request body contains invalid json. + + Request: + --- + #{request} + --- + MESSAGE + end + + it "returns `error` with message" do + expect(result).to be_error.with_message(error_message) + end end end - context "when request body is valid for both HTTP and then JSON parsing" do + context "when `ExtractParamsFromBody` is successful" do let(:http_string) do <<~TEXT POST /rules/1000000.json HTTP/1.1 @@ -105,7 +107,7 @@ } end - it "returns success with params with symbolized keys" do + it "returns `success` with params with symbolized keys" do expect(result).to be_success.with_data(params: params) end end diff --git a/spec/lib/convenient_service/examples/standard/v1/request_params/services/extract_params_from_path_spec.rb b/spec/lib/convenient_service/examples/standard/v1/request_params/services/extract_params_from_path_spec.rb index 366a55460c2..55d06be4c0a 100644 --- a/spec/lib/convenient_service/examples/standard/v1/request_params/services/extract_params_from_path_spec.rb +++ b/spec/lib/convenient_service/examples/standard/v1/request_params/services/extract_params_from_path_spec.rb @@ -6,10 +6,10 @@ # rubocop:disable RSpec/NestedGroups, RSpec/MultipleMemoizedHelpers RSpec.describe ConvenientService::Examples::Standard::V1::RequestParams::Services::ExtractParamsFromPath do + include ConvenientService::RSpec::Matchers::Results + example_group "class methods" do describe ".result" do - include ConvenientService::RSpec::Matchers::Results - subject(:result) { described_class.result(request: request, pattern: pattern) } let(:request) { ConvenientService::Examples::Standard::V1::RequestParams::Entities::Request.new(http_string: http_string) } @@ -31,43 +31,45 @@ TEXT end - context "when request is NOT valid for HTTP parsing" do - let(:path) { "abc" } + context "when `ExtractParamsFromPath` is NOT successful" do + context "when request is NOT valid for HTTP parsing" do + let(:path) { "abc" } - let(:error_message) do - <<~MESSAGE - Failed to resolve path since request is NOT HTTP parsable. + let(:error_message) do + <<~MESSAGE + Failed to resolve path since request is NOT HTTP parsable. - Request: - --- - #{request} - --- - MESSAGE - end + Request: + --- + #{request} + --- + MESSAGE + end - it "fails to parse request path" do - expect(result).to be_error.with_message(error_message) + it "returns error with message" do + expect(result).to be_error.with_message(error_message) + end end - end - context "when request path does NOT match pattern" do - let(:id) { "abc" } - let(:format) { "json" } + context "when request path does NOT match pattern" do + let(:id) { "abc" } + let(:format) { "json" } - let(:error_message) { "Path `#{path}` does NOT match pattern `#{pattern}`." } + let(:error_message) { "Path `#{path}` does NOT match pattern `#{pattern}`." } - it "fails to parse JSON from request body" do - expect(result).to be_error.with_message(error_message) + it "returns error with message" do + expect(result).to be_error.with_message(error_message) + end end end - context "when request path matches pattern" do + context "when `ExtractParamsFromPath` is successful" do let(:id) { "1000000" } let(:format) { "json" } let(:params) { {id: id, format: format} } - it "returns success with params with symbolized keys" do + it "returns `success` with params with symbolized keys" do expect(result).to be_success.with_data(params: params) end end diff --git a/spec/lib/convenient_service/examples/standard/v1/request_params/services/filter_out_unpermitted_params_spec.rb b/spec/lib/convenient_service/examples/standard/v1/request_params/services/filter_out_unpermitted_params_spec.rb index 2ea8df9e1c5..817c5129ce1 100644 --- a/spec/lib/convenient_service/examples/standard/v1/request_params/services/filter_out_unpermitted_params_spec.rb +++ b/spec/lib/convenient_service/examples/standard/v1/request_params/services/filter_out_unpermitted_params_spec.rb @@ -6,27 +6,29 @@ # rubocop:disable RSpec/NestedGroups RSpec.describe ConvenientService::Examples::Standard::V1::RequestParams::Services::FilterOutUnpermittedParams do + include ConvenientService::RSpec::Matchers::Results + example_group "class methods" do describe ".result" do - include ConvenientService::RSpec::Matchers::Results - subject(:result) { described_class.result(params: params, permitted_keys: permitted_keys) } let(:params) { {id: "1000000", title: "Check the official User Docs", verified: true} } - context "when params does NOT only permitted keys" do - let(:permitted_keys) { [:id, :title] } + context "when `FilterOutUnpermittedParams` is successful" do + context "when `params` do NOT have only permitted keys" do + let(:permitted_keys) { [:id, :title] } - it "returns success with `params` without unpermitted keys" do - expect(result).to be_success.with_data(params: params.slice(*permitted_keys)) + it "returns `success` with `params` without unpermitted keys" do + expect(result).to be_success.with_data(params: params.slice(*permitted_keys)) + end end - end - context "when `params` have only permitted keys" do - let(:permitted_keys) { [:id, :title, :verified] } + context "when `params` have only permitted keys" do + let(:permitted_keys) { [:id, :title, :verified] } - it "returns success with original `params`" do - expect(result).to be_success.with_data(params: params) + it "returns `success` with original `params`" do + expect(result).to be_success.with_data(params: params) + end end end end diff --git a/spec/lib/convenient_service/examples/standard/v1/request_params/services/log_request_params_spec.rb b/spec/lib/convenient_service/examples/standard/v1/request_params/services/log_request_params_spec.rb index 8e39e1d5343..9a10c43ccb0 100644 --- a/spec/lib/convenient_service/examples/standard/v1/request_params/services/log_request_params_spec.rb +++ b/spec/lib/convenient_service/examples/standard/v1/request_params/services/log_request_params_spec.rb @@ -6,78 +6,45 @@ # rubocop:disable RSpec/NestedGroups RSpec.describe ConvenientService::Examples::Standard::V1::RequestParams::Services::LogRequestParams do + include ConvenientService::RSpec::Matchers::DelegateTo + include ConvenientService::RSpec::Matchers::Results + example_group "class methods" do describe ".result" do - include ConvenientService::RSpec::Matchers::DelegateTo - include ConvenientService::RSpec::Matchers::Results - - subject(:result) { described_class.result(request: request, params: params) } - - let(:request) { ConvenientService::Examples::Standard::V1::RequestParams::Entities::Request.new(http_string: http_string) } - - let(:http_string) do - <<~TEXT - POST /rules/1000000.json HTTP/1.1 - User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 - Host: code-review.com - Content-Type: application/json; charset=utf-8 - Content-Length: 105 - Accept-Language: en-us - Accept-Encoding: gzip, deflate - Connection: Keep-Alive - - {"title":"Avoid error shadowing","description":"Check the official User Docs","tags":["error-shadowing"]} - TEXT - end - - let(:params) do - { - id: "1000000", - format: "html", - title: "Avoid error shadowing", - description: "Check the official User Docs", - tags: "ruby", - sources: "https://www.rubyguides.com/2019/07/ruby-instance-variables/" - } - end + context "when `LogRequestParams` is successful" do + subject(:result) { described_class.result(request: request, params: params) } + + let(:request) { ConvenientService::Examples::Standard::V1::RequestParams::Entities::Request.new(http_string: http_string) } + + let(:http_string) do + <<~TEXT + POST /rules/1000000.json HTTP/1.1 + User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 + Host: code-review.com + Content-Type: application/json; charset=utf-8 + Content-Length: 105 + Accept-Language: en-us + Accept-Encoding: gzip, deflate + Connection: Keep-Alive + + {"title":"Avoid error shadowing","description":"Check the official User Docs","tags":["error-shadowing"]} + TEXT + end - let(:message) do - <<~MESSAGE - [Thread##{Thread.current.object_id}] [Request##{request.object_id}] [Params]: + let(:params) do { - id: #{params[:id].inspect}, - format: #{params[:format].inspect}, - title: #{params[:title].inspect}, - description: #{params[:description].inspect}, - tags: #{params[:tags].inspect}, - sources: #{params[:sources].inspect} + id: "1000000", + format: "html", + title: "Avoid error shadowing", + description: "Check the official User Docs", + tags: "ruby", + sources: "https://www.rubyguides.com/2019/07/ruby-instance-variables/" } - MESSAGE - end - - before do - allow(ConvenientService::Examples::Standard::V1::RequestParams::Entities::Logger).to receive(:log) - end - - it "logs message" do - expect { result } - .to delegate_to(ConvenientService::Examples::Standard::V1::RequestParams::Entities::Logger, :log) - .with_arguments(message) - .without_calling_original - end - - it "returns success" do - expect(result).to be_success.without_data - end - - context "when tag is passed" do - subject(:result) { described_class.result(request: request, params: params, tag: tag) } - - let(:tag) { "Uncasted" } + end let(:message) do <<~MESSAGE - [Thread##{Thread.current.object_id}] [Request##{request.object_id}] [Params] [#{tag}]: + [Thread##{Thread.current.object_id}] [Request##{request.object_id}] [Params]: { id: #{params[:id].inspect}, format: #{params[:format].inspect}, @@ -89,12 +56,47 @@ MESSAGE end - it "logs message with tag" do + before do + allow(ConvenientService::Examples::Standard::V1::RequestParams::Entities::Logger).to receive(:log) + end + + it "returns `success`" do + expect(result).to be_success.without_data + end + + it "logs message" do expect { result } .to delegate_to(ConvenientService::Examples::Standard::V1::RequestParams::Entities::Logger, :log) .with_arguments(message) .without_calling_original end + + context "when tag is passed" do + subject(:result) { described_class.result(request: request, params: params, tag: tag) } + + let(:tag) { "Uncasted" } + + let(:message) do + <<~MESSAGE + [Thread##{Thread.current.object_id}] [Request##{request.object_id}] [Params] [#{tag}]: + { + id: #{params[:id].inspect}, + format: #{params[:format].inspect}, + title: #{params[:title].inspect}, + description: #{params[:description].inspect}, + tags: #{params[:tags].inspect}, + sources: #{params[:sources].inspect} + } + MESSAGE + end + + it "logs message with tag" do + expect { result } + .to delegate_to(ConvenientService::Examples::Standard::V1::RequestParams::Entities::Logger, :log) + .with_arguments(message) + .without_calling_original + end + end end end end diff --git a/spec/lib/convenient_service/examples/standard/v1/request_params/services/merge_params_spec.rb b/spec/lib/convenient_service/examples/standard/v1/request_params/services/merge_params_spec.rb index 643768f11d6..5bd316f2b8c 100644 --- a/spec/lib/convenient_service/examples/standard/v1/request_params/services/merge_params_spec.rb +++ b/spec/lib/convenient_service/examples/standard/v1/request_params/services/merge_params_spec.rb @@ -6,42 +6,17 @@ # rubocop:disable RSpec/NestedGroups RSpec.describe ConvenientService::Examples::Standard::V1::RequestParams::Services::MergeParams do + include ConvenientService::RSpec::Matchers::Results + example_group "class methods" do describe ".result" do - include ConvenientService::RSpec::Matchers::Results - - subject(:result) { described_class.result(params_from_path: params_from_path, params_from_body: params_from_body) } - - let(:params_from_path) { {id: 1, format: "html"} } - - let(:params_from_body) do - { - title: "Avoid error shadowing", - description: "Check the official User Docs", - tags: "ruby", - sources: "https://www.rubyguides.com/2019/07/ruby-instance-variables/" - } - end - - let(:merged_params) do - { - id: 1, - format: "html", - title: "Avoid error shadowing", - description: "Check the official User Docs", - tags: "ruby", - sources: "https://www.rubyguides.com/2019/07/ruby-instance-variables/" - } - end + context "when `MergeParams` is successful" do + subject(:result) { described_class.result(params_from_path: params_from_path, params_from_body: params_from_body) } - it "returns success with original merged params" do - expect(result).to be_success.with_data(params: merged_params) - end + let(:params_from_path) { {id: 1, format: "html"} } - context "when `params_from_path` and `params_from_body` have same keys" do let(:params_from_body) do { - format: "json", title: "Avoid error shadowing", description: "Check the official User Docs", tags: "ruby", @@ -52,7 +27,7 @@ let(:merged_params) do { id: 1, - format: "json", + format: "html", title: "Avoid error shadowing", description: "Check the official User Docs", tags: "ruby", @@ -60,9 +35,36 @@ } end - it "takes value from `params_from_body`" do + it "returns `success` with original merged params" do expect(result).to be_success.with_data(params: merged_params) end + + context "when `params_from_path` and `params_from_body` have same keys" do + let(:params_from_body) do + { + format: "json", + title: "Avoid error shadowing", + description: "Check the official User Docs", + tags: "ruby", + sources: "https://www.rubyguides.com/2019/07/ruby-instance-variables/" + } + end + + let(:merged_params) do + { + id: 1, + format: "json", + title: "Avoid error shadowing", + description: "Check the official User Docs", + tags: "ruby", + sources: "https://www.rubyguides.com/2019/07/ruby-instance-variables/" + } + end + + it "takes value from `params_from_body`" do + expect(result).to be_success.with_data(params: merged_params) + end + end end end end diff --git a/spec/lib/convenient_service/examples/standard/v1/request_params/services/prepare_spec.rb b/spec/lib/convenient_service/examples/standard/v1/request_params/services/prepare_spec.rb index 99b2df7ebea..ded5c54ebfb 100644 --- a/spec/lib/convenient_service/examples/standard/v1/request_params/services/prepare_spec.rb +++ b/spec/lib/convenient_service/examples/standard/v1/request_params/services/prepare_spec.rb @@ -6,11 +6,11 @@ # rubocop:disable RSpec/NestedGroups, RSpec/MultipleMemoizedHelpers RSpec.describe ConvenientService::Examples::Standard::V1::RequestParams::Services::Prepare do + include ConvenientService::RSpec::Matchers::DelegateTo + include ConvenientService::RSpec::Matchers::Results + example_group "class methods" do describe ".result" do - include ConvenientService::RSpec::Matchers::DelegateTo - include ConvenientService::RSpec::Matchers::Results - subject(:result) { described_class.result(request: request) } let(:request) { ConvenientService::Examples::Standard::V1::RequestParams::Entities::Request.new(http_string: http_string) } @@ -49,13 +49,9 @@ end let(:path) { "/rules/%{id}.%{format}" % path_params } - let(:path_params) { {id: id, format: format} } - let(:id) { "1000000" } - let(:format) { "json" } - let(:body) { JSON.generate(json_body) } let(:json_body) do @@ -69,13 +65,9 @@ end let(:body_params) { json_body.transform_keys(&:to_sym) } - let(:merged_params) { path_params.merge(body_params) } - let(:permitted_params) { merged_params.slice(*(merged_params.keys - [:verified])) } - let(:params_with_defaults) { defaults.merge(permitted_params) } - let(:original_params) { params_with_defaults } let(:casted_params) do @@ -96,101 +88,85 @@ allow(ConvenientService::Examples::Standard::V1::RequestParams::Entities::Logger).to receive(:log).with(anything) end - context "when request is NOT valid to extract params from path" do - ## - # Contains invalid path. - # https://www.w3.org/TR/2011/WD-html5-20110525/urls.html - # - let(:path) { "/ru*les/1.json" } - let(:pattern) { /^\/rules\/(?\d+)\.(?\w+)$/ } + context "when `Prepare` is NOT successful" do + context "when `ExtractParamsFromPath` is NOT successful" do + ## + # Contains invalid path. + # https://www.w3.org/TR/2011/WD-html5-20110525/urls.html + # + let(:path) { "/ru*les/1.json" } + let(:pattern) { /^\/rules\/(?\d+)\.(?\w+)$/ } - it "fails to extract params from path" do - expect(result).to be_error.of_step(ConvenientService::Examples::Standard::V1::RequestParams::Services::ExtractParamsFromPath) + it "returns intermediate step result" do + expect(result).to be_not_success.of_step(ConvenientService::Examples::Standard::V1::RequestParams::Services::ExtractParamsFromPath) + end end - end - context "when request is NOT valid to extract params from body" do - ## - # Contains unparsable JSON body. - # - let(:body) { "abc" } + context "when `ExtractParamsFromBody` is NOT successful" do + ## + # Contains unparsable JSON body. + # + let(:body) { "abc" } - it "fails to extract params from body" do - expect(result).to be_error.of_step(ConvenientService::Examples::Standard::V1::RequestParams::Services::ExtractParamsFromBody) + it "returns intermediate step result" do + expect(result).to be_not_success.of_step(ConvenientService::Examples::Standard::V1::RequestParams::Services::ExtractParamsFromBody) + end end - end - context "when request is valid to extract params from both path and body" do - it "merges params extracted from path and body" do + context "when uncasted params are NOT valid" do ## - # TODO: Introduce `delegate_to_service` to hide `commit_config!`. + # Contains unsupported format, only JSON is available. # - ConvenientService::Examples::Standard::V1::RequestParams::Services::MergeParams.commit_config! + let(:path) { "/rules/1.html" } + + it "returns intermediate step result" do + expect(result).to be_not_success.of_step(ConvenientService::Examples::Standard::V1::RequestParams::Services::ValidateUncastedParams) + end + end + + context "when casted params are NOT valid" do + before do + allow(ConvenientService::Examples::Standard::V1::RequestParams::Entities::ID).to receive(:cast).and_return(nil) + end + it "returns intermediate step result" do + expect(result).to be_not_success.of_step(ConvenientService::Examples::Standard::V1::RequestParams::Services::ValidateCastedParams) + end + end + end + + context "when `Prepare` is successful" do + specify do expect { result } .to delegate_to(ConvenientService::Examples::Standard::V1::RequestParams::Services::MergeParams, :result) .with_arguments(params_from_path: path_params, params_from_body: body_params) end - it "logs merged params from path and body with \"Uncasted\" tag" do - ## - # TODO: Introduce `delegate_to_service` to hide `commit_config!`. - # - ConvenientService::Examples::Standard::V1::RequestParams::Services::LogRequestParams.commit_config! - + specify do expect { result } .to delegate_to(ConvenientService::Examples::Standard::V1::RequestParams::Services::LogRequestParams, :result) .with_arguments(request: request, params: merged_params, tag: "Uncasted") end - it "filters out unpermitted keys" do - ConvenientService::Examples::Standard::V1::RequestParams::Services::FilterOutUnpermittedParams.commit_config! - + specify do expect { result } .to delegate_to(ConvenientService::Examples::Standard::V1::RequestParams::Services::FilterOutUnpermittedParams, :result) .with_arguments(params: merged_params, permitted_keys: permitted_keys) end - it "applies default values" do - ConvenientService::Examples::Standard::V1::RequestParams::Services::ApplyDefaultParamValues.commit_config! - + specify do expect { result } .to delegate_to(ConvenientService::Examples::Standard::V1::RequestParams::Services::ApplyDefaultParamValues, :result) .with_arguments(params: permitted_params, defaults: defaults) end - end - - context "when uncasted params are NOT valid" do - ## - # Contains unsupported format, only JSON is available. - # - let(:path) { "/rules/1.html" } - it "fails to validate uncasted params" do - expect(result).to be_error.of_step(ConvenientService::Examples::Standard::V1::RequestParams::Services::ValidateUncastedParams) - end - end - - context "when uncasted params are valid" do - it "logs casted params with \"Casted\" tag" do + specify do expect { result } .to delegate_to(ConvenientService::Examples::Standard::V1::RequestParams::Services::LogRequestParams, :result) .with_arguments(request: request, params: casted_params, tag: "Casted") end - end - - context "when casted params are NOT valid" do - before do - allow(ConvenientService::Examples::Standard::V1::RequestParams::Entities::ID).to receive(:cast).and_return(nil) - end - - it "fails to validate casted params" do - expect(result).to be_error.of_step(ConvenientService::Examples::Standard::V1::RequestParams::Services::ValidateCastedParams) - end - end - context "when casted params are valid" do - it "returns success with casted params" do + it "returns `success` with casted params" do expect(result).to be_success.with_data(params: casted_params) end end diff --git a/spec/lib/convenient_service/examples/standard/v1/request_params/services/validate_casted_params_spec.rb b/spec/lib/convenient_service/examples/standard/v1/request_params/services/validate_casted_params_spec.rb index 88c3c27f728..03404bed0b0 100644 --- a/spec/lib/convenient_service/examples/standard/v1/request_params/services/validate_casted_params_spec.rb +++ b/spec/lib/convenient_service/examples/standard/v1/request_params/services/validate_casted_params_spec.rb @@ -6,10 +6,10 @@ # rubocop:disable RSpec/NestedGroups, RSpec/MultipleMemoizedHelpers RSpec.describe ConvenientService::Examples::Standard::V1::RequestParams::Services::ValidateCastedParams do + include ConvenientService::RSpec::Matchers::Results + example_group "class methods" do describe ".result" do - include ConvenientService::RSpec::Matchers::Results - subject(:result) { described_class.result(original_params: original_params, casted_params: casted_params) } let(:original_params) do @@ -48,41 +48,43 @@ let(:casted_tags) { [ConvenientService::Examples::Standard::V1::RequestParams::Entities::Tag.cast(original_params[:tags])] } let(:casted_sources) { [ConvenientService::Examples::Standard::V1::RequestParams::Entities::Source.cast(original_params[:sources])] } - context "when params are NOT valid" do - context "when original id is NOT castable" do - let(:original_id) { nil } + context "when `ValidateCastedParams` is NOT successful" do + context "when params are NOT valid" do + context "when original id is NOT castable" do + let(:original_id) { nil } - it "returns error with message" do - expect(result).to be_error.with_message("Failed to cast `#{original_id.inspect}` into `ID`") + it "returns `error` with `message`" do + expect(result).to be_error.with_message("Failed to cast `#{original_id.inspect}` into `ID`") + end end - end - context "when original format is NOT castable" do - let(:casted_format) { nil } + context "when original format is NOT castable" do + let(:casted_format) { nil } - it "returns error with message" do - expect(result).to be_error.with_message("Failed to cast `#{original_format.inspect}` into `Format`") + it "returns `error` with `message`" do + expect(result).to be_error.with_message("Failed to cast `#{original_format.inspect}` into `Format`") + end end - end - context "when original title is NOT castable" do - let(:casted_title) { nil } + context "when original title is NOT castable" do + let(:casted_title) { nil } - it "returns error with message" do - expect(result).to be_error.with_message("Failed to cast `#{original_title.inspect}` into `Title`") + it "returns `error` with `message`" do + expect(result).to be_error.with_message("Failed to cast `#{original_title.inspect}` into `Title`") + end end - end - context "when original description is NOT castable" do - let(:casted_description) { nil } + context "when original description is NOT castable" do + let(:casted_description) { nil } - it "returns error with message" do - expect(result).to be_error.with_message("Failed to cast `#{original_description.inspect}` into `Description`") + it "returns `error` with `message`" do + expect(result).to be_error.with_message("Failed to cast `#{original_description.inspect}` into `Description`") + end end end end - context "when params are valid" do + context "when `ValidateCastedParams` is successful" do it "returns success without data" do expect(result).to be_success.without_data end diff --git a/spec/lib/convenient_service/examples/standard/v1/request_params/services/validate_uncasted_params_spec.rb b/spec/lib/convenient_service/examples/standard/v1/request_params/services/validate_uncasted_params_spec.rb index c61f1047347..bbd8dfeda64 100644 --- a/spec/lib/convenient_service/examples/standard/v1/request_params/services/validate_uncasted_params_spec.rb +++ b/spec/lib/convenient_service/examples/standard/v1/request_params/services/validate_uncasted_params_spec.rb @@ -6,10 +6,10 @@ # rubocop:disable RSpec/NestedGroups, RSpec/MultipleMemoizedHelpers RSpec.describe ConvenientService::Examples::Standard::V1::RequestParams::Services::ValidateUncastedParams do + include ConvenientService::RSpec::Matchers::Results + example_group "class methods" do describe ".result" do - include ConvenientService::RSpec::Matchers::Results - subject(:result) { described_class.result(params: params) } let(:params) do @@ -30,50 +30,52 @@ let(:tags) { "ruby" } let(:sources) { "https://www.rubyguides.com/2019/07/ruby-instance-variables/" } - context "when params are NOT valid" do - context "when ID is NOT present" do - let(:id) { "" } + context "when `ValidateUncastedParams` is NOT successful" do + context "when params are NOT valid" do + context "when ID is NOT present" do + let(:id) { "" } - it "returns error with message" do - expect(result).to be_error.with_message("ID is NOT present") + it "returns `error` with `message`" do + expect(result).to be_error.with_message("ID is NOT present") + end end - end - context "when ID is NOT valid integer" do - let(:id) { "abc" } + context "when ID is NOT valid integer" do + let(:id) { "abc" } - it "returns error with message" do - expect(result).to be_error.with_message("ID `#{id}` is NOT a valid integer") + it "returns `error` with `message`" do + expect(result).to be_error.with_message("ID `#{id}` is NOT a valid integer") + end end - end - context "when format is NOT json" do - let(:format) { "html" } + context "when format is NOT json" do + let(:format) { "html" } - it "returns error with message" do - expect(result).to be_error.with_message("Format `#{format}` is NOT supported, only JSON is allowed") + it "returns `error` with `message`" do + expect(result).to be_error.with_message("Format `#{format}` is NOT supported, only JSON is allowed") + end end - end - context "when title is NOT present" do - let(:title) { "" } + context "when title is NOT present" do + let(:title) { "" } - it "returns error with message" do - expect(result).to be_error.with_message("Title is NOT present") + it "returns `error` with `message`" do + expect(result).to be_error.with_message("Title is NOT present") + end end - end - context "when description is NOT present" do - let(:description) { "" } + context "when description is NOT present" do + let(:description) { "" } - it "returns error with message" do - expect(result).to be_error.with_message("Description is NOT present") + it "returns `error` with `message`" do + expect(result).to be_error.with_message("Description is NOT present") + end end end end - context "when params are valid" do - it "returns success without data" do + context "when `ValidateUncastedParams` is successful" do + it "returns `success` without data" do expect(result).to be_success.without_data end end