diff --git a/spec/controllers/shopify/callbacks_controller_spec.rb b/spec/controllers/shopify/callbacks_controller_spec.rb index cb75e23b4..c57440347 100644 --- a/spec/controllers/shopify/callbacks_controller_spec.rb +++ b/spec/controllers/shopify/callbacks_controller_spec.rb @@ -9,6 +9,13 @@ RSpec.describe Shopify::CallbacksController, type: :request do let(:shopify_redirect_uri) { "#{frontend_url}/app/accounts/#{account.id}/settings/integrations/shopify" } let(:oauth_client) { instance_double(OAuth2::Client) } let(:auth_code_strategy) { instance_double(OAuth2::Strategy::AuthCode) } + let(:token_response) do + instance_double( + OAuth2::AccessToken, + response: instance_double(OAuth2::Response, parsed: response_body), + token: access_token + ) + end describe 'GET /shopify/callback' do let(:access_token) { SecureRandom.hex(10) } @@ -23,12 +30,24 @@ RSpec.describe Shopify::CallbacksController, type: :request do stub_const('ENV', ENV.to_hash.merge('FRONTEND_URL' => frontend_url)) end - context 'when successful' do + shared_context 'with stubbed account' do before do - controller = described_class.new - allow(controller).to receive(:verify_shopify_token).with(state).and_return(account.id) - allow(described_class).to receive(:new).and_return(controller) + allow(described_class).to receive(:new).and_wrap_original do |original, *args| + controller = original.call(*args) + allow(controller).to receive(:verify_shopify_token).and_return(account.id) + allow(controller).to receive(:oauth_client).and_return(oauth_client) + controller + end + allow(Account).to receive(:find).and_return(account) + allow(oauth_client).to receive(:auth_code).and_return(auth_code_strategy) + end + end + + context 'when successful' do + include_context 'with stubbed account' + before do + allow(auth_code_strategy).to receive(:get_token).and_return(token_response) stub_request(:post, "https://#{shop}/admin/oauth/access_token") .to_return( status: 200, @@ -55,12 +74,11 @@ RSpec.describe Shopify::CallbacksController, type: :request do end context 'when the code is missing' do + include_context 'with stubbed account' before do - controller = described_class.new - allow(controller).to receive(:verify_shopify_token).with(state).and_return(account.id) - allow(controller).to receive(:oauth_client).and_return(oauth_client) - allow(oauth_client).to receive(:auth_code).and_raise(StandardError) - allow(described_class).to receive(:new).and_return(controller) + allow(auth_code_strategy).to receive(:get_token).and_raise(StandardError) + stub_request(:post, "https://#{shop}/admin/oauth/access_token") + .to_return(status: 400, body: { error: 'invalid_grant' }.to_json) end it 'redirects to the shopify_redirect_uri with error' do @@ -70,11 +88,8 @@ RSpec.describe Shopify::CallbacksController, type: :request do end context 'when the token is invalid' do + include_context 'with stubbed account' before do - controller = described_class.new - allow(controller).to receive(:verify_shopify_token).with(state).and_return(account.id) - allow(controller).to receive(:oauth_client).and_return(oauth_client) - allow(oauth_client).to receive(:auth_code).and_return(auth_code_strategy) allow(auth_code_strategy).to receive(:get_token).and_raise( OAuth2::Error.new( OpenStruct.new( @@ -83,7 +98,9 @@ RSpec.describe Shopify::CallbacksController, type: :request do ) ) ) - allow(described_class).to receive(:new).and_return(controller) + + stub_request(:post, "https://#{shop}/admin/oauth/access_token") + .to_return(status: 400, body: { error: 'invalid_grant' }.to_json) end it 'redirects to the shopify_redirect_uri with error' do @@ -94,10 +111,11 @@ RSpec.describe Shopify::CallbacksController, type: :request do context 'when state parameter is invalid' do before do - controller = described_class.new - allow(controller).to receive(:verify_shopify_token).with(state).and_return(nil) - allow(controller).to receive(:account).and_return(nil) - allow(described_class).to receive(:new).and_return(controller) + # rubocop:disable RSpec/AnyInstance, RSpec/DescribedClass + # Explicit class name and any_instance required for parallel CI stability + allow_any_instance_of(Shopify::CallbacksController).to receive(:verify_shopify_token).and_return(nil) + allow_any_instance_of(Shopify::CallbacksController).to receive(:account).and_return(nil) + # rubocop:enable RSpec/AnyInstance, RSpec/DescribedClass end it 'redirects to the frontend URL with error' do diff --git a/spec/services/crm/leadsquared/api/base_client_spec.rb b/spec/services/crm/leadsquared/api/base_client_spec.rb index e88fd04c5..132ca81ff 100644 --- a/spec/services/crm/leadsquared/api/base_client_spec.rb +++ b/spec/services/crm/leadsquared/api/base_client_spec.rb @@ -63,10 +63,10 @@ RSpec.describe Crm::Leadsquared::Api::BaseClient do end it 'raises ApiError with error message' do - expect { client.get(path, params) }.to raise_error( - Crm::Leadsquared::Api::BaseClient::ApiError, - 'Invalid lead ID' - ) + expect { client.get(path, params) }.to raise_error do |error| + expect(error.class.name).to eq(described_class::ApiError.name) + expect(error.message).to eq('Invalid lead ID') + end end end @@ -82,7 +82,7 @@ RSpec.describe Crm::Leadsquared::Api::BaseClient do it 'raises ApiError with status code' do expect { client.get(path, params) }.to raise_error do |error| - expect(error).to be_a(Crm::Leadsquared::Api::BaseClient::ApiError) + expect(error.class.name).to eq(described_class::ApiError.name) expect(error.message).to include('Not Found') expect(error.code).to eq(404) end @@ -134,10 +134,10 @@ RSpec.describe Crm::Leadsquared::Api::BaseClient do end it 'raises ApiError with error message' do - expect { client.post(path, params, body) }.to raise_error( - Crm::Leadsquared::Api::BaseClient::ApiError, - 'Invalid data' - ) + expect { client.post(path, params, body) }.to raise_error do |error| + expect(error.class.name).to eq(described_class::ApiError.name) + expect(error.message).to eq('Invalid data') + end end end @@ -158,7 +158,7 @@ RSpec.describe Crm::Leadsquared::Api::BaseClient do it 'raises ApiError for invalid JSON' do expect { client.post(path, params, body) }.to raise_error do |error| - expect(error).to be_a(Crm::Leadsquared::Api::BaseClient::ApiError) + expect(error.class.name).to eq(described_class::ApiError.name) expect(error.message).to include('Failed to parse') end end @@ -177,7 +177,7 @@ RSpec.describe Crm::Leadsquared::Api::BaseClient do it 'raises ApiError with status code' do expect { client.post(path, params, body) }.to raise_error do |error| - expect(error).to be_a(Crm::Leadsquared::Api::BaseClient::ApiError) + expect(error.class.name).to eq(described_class::ApiError.name) expect(error.message).to include('Internal Server Error') expect(error.code).to eq(500) end