# frozen_string_literal: true describe 'Api::V2::Resources::Phones' do include_context 'bearer authentication' let!(:create_member_permission) do create :permission, role: 'member' end context 'Twilio Verify Service' do before do allow(Barong::App.config).to receive(:twilio_provider).and_return(TwilioVerifyService) end describe 'GET /api/v2/resource/phones' do let!(:phone1) { create(:phone, user: test_user) } let!(:phone2) { create(:phone, user: test_user, number: 12345677711 ) } let(:do_request) do get '/api/v2/resource/phones', headers: auth_header end it 'returns list of user\'s phones' do do_request expect(json_body.length).to eq 2 expect(json_body.first[:number]).to eq phone1.sub_masked_number expect(json_body.first[:country]).to eq phone1.country expect(json_body.first[:validated_at]).to eq phone1.validated_at expect(json_body.second[:number]).to eq phone2.sub_masked_number expect(json_body.second[:country]).to eq phone2.country expect(json_body.second[:validated_at]).to eq phone2.validated_at end context 'list of users phone without masking' do before do Barong::App.config.stub(:api_data_masking_enabled).and_return(false) end it 'returns list of user\'s phones' do do_request expect(json_body.length).to eq 2 expect(json_body.first[:number]).to eq phone1.number expect(json_body.first[:country]).to eq phone1.country expect(json_body.first[:validated_at]).to eq phone1.validated_at expect(json_body.second[:number]).to eq phone2.number expect(json_body.second[:country]).to eq phone2.country expect(json_body.second[:validated_at]).to eq phone2.validated_at end end end describe 'POST /api/v2/resource/phones' do let(:do_request) do post '/api/v2/resource/phones', params: params, headers: auth_header end let(:phone_number) { nil } let(:params) { { phone_number: phone_number, channel: 'sms' } } describe 'errors: ' do context 'when phone is missing' do let(:phone_number) { nil } it 'renders an error' do do_request expect_body.to eq(errors: ["resource.phone.empty_phone_number"]) expect_status.to eq 422 end end context 'when phone is invalid' do let(:phone_number) { '123' } it 'renders an error' do do_request expect_body.to eq(errors: ["resource.phone.invalid_num"]) expect_status.to eq 400 end end context 'when phone is already exists' do let!(:phone) do create(:phone, validated_at: validated_at) end let(:phone_number) { phone.number } context 'when phone verified' do let(:validated_at) { 1.minutes.ago } it 'renders an error' do do_request expect_body.to eq(errors: ["resource.phone.number_exist"]) expect_status.to eq 400 end end context 'when phone is not verified' do let(:validated_at) { 1.minutes.ago } it 'renders an error' do do_request expect_body.to eq(errors: ["resource.phone.number_exist"]) expect_status.to eq 400 end end context 'when phone verified but number is not sanitized' do let(:validated_at) { 1.minutes.ago } let(:phone_number) { "++#{phone.number}" } it 'renders an error' do do_request expect_body.to eq(errors: ["resource.phone.number_exist"]) expect_status.to eq 400 end end end end context 'valid story' do before do allow(Barong::App.config.twilio_provider).to receive(:send_code).and_return(false) end context 'when phone is not verified' do let(:phone_number) { build(:phone).number } it 'assigns a phone to account and send sms' do do_request expect_body.to eq(message: 'Code was sent successfully via sms') expect_status.to eq 201 end end context 'when phone is valid' do let(:phone_number) { build(:phone).number } it 'creates a phone and send code via sms channel' do do_request expect_body.to eq(message: 'Code was sent successfully via sms') expect_status.to eq 201 end it 'creates a phone and send code via call channel' do params['channel'] = 'call' do_request expect_body.to eq(message: 'Code was sent successfully via call') expect_status.to eq 201 end end end context 'when phone is on national format with zero' do let(:phone_number) { '+44 07418084106' } let(:international_phone) { '447418084106' } it 'creates a phone and send sms' do allow(Barong::App.config.twilio_provider).to receive(:send_code).and_return(false) do_request expect_body.to eq(message: 'Code was sent successfully via sms') expect_status.to eq 201 expect(Phone.last.number).to eq(international_phone) end end context 'when phone exists on international format' do let(:phone_number) { '+44 07418084106' } let(:international_phone) { '447418084106' } let!(:phone) do create(:phone, validated_at: 1.minute.ago, number: international_phone) end it 'renders an error' do do_request expect_body.to eq errors: ["resource.phone.number_exist"] expect_status.to eq 400 end end end describe 'POST /api/v2/resource/phones/verify' do let(:do_request) do post '/api/v2/resource/phones/verify', params: params, headers: auth_header end let(:params) do { phone_number: phone_number, verification_code: verification_code } end let(:verification_code) { '12345' } context 'when phone is missing and code is missing' do let(:phone_number) { nil } let(:verification_code) { '' } it 'renders an error' do do_request expect_body.to eq(errors: ["resource.phone.empty_phone_number", "resource.phone.empty_verification_code"]) expect_status.to eq 422 end end context 'when phone is invalid' do let(:phone_number) { '123' } it 'renders an error' do do_request expect_body.to eq(errors: ["resource.phone.invalid_num"]) expect_status.to eq 400 end end context 'when phone is already exists and verified' do let!(:phone) do create(:phone, validated_at: 1.minutes.ago) end let(:phone_number) { phone.number } it 'renders an error' do do_request expect_body.to eq(errors: ["resource.phone.number_exist"]) expect_status.to eq 400 end end context 'when phone exists in international format' do let!(:phone) do create(:phone, validated_at: 1.minutes.ago, number: international_phone) end let(:phone_number) { '+44 07418084106' } let(:international_phone) { '447418084106' } it 'renders an error' do do_request expect_body.to eq(errors: ["resource.phone.number_exist"]) expect_status.to eq 400 end end context 'when phone is not found in test_user' do let!(:phone) { create(:phone) } let(:phone_number) { phone.number } it 'rendens an error' do allow(Barong::App.config.twilio_provider).to receive(:verify_code?).and_return(false) do_request expect_body.to eq(errors: ["resource.phone.doesnt_exist"]) expect_status.to eq 404 end end context 'when phone is found in test_user but code is invalid' do let!(:phone) { create(:phone, user: test_user) } let(:phone_number) { phone.number } it 'rendens an error' do allow(Barong::App.config.twilio_provider).to receive(:verify_code?).and_return(false) do_request expect_body.to eq(errors: ["resource.phone.verification_invalid"]) expect_status.to eq 404 end end context 'when phone and code is valid' do let(:phone) { create(:phone, user: test_user) } let(:phone_number) { phone.number } it 'responses with success' do allow(Barong::App.config.twilio_provider).to receive(:verify_code?).and_return(true) set_level(test_user, 1) do_request expect_status.to eq 201 expect(phone.reload.validated_at).to be test_user.update_level expect(test_user.reload.level).to eq 2 end end end end context 'With Twilio SMS Sender service' do let(:phone_number) { phone.number } let(:do_request) do post '/api/v2/resource/phones', params: params, headers: auth_header end let(:params) { { phone_number: phone_number, channel: 'sms' } } let(:verification_code) { '12345' } context 'valid story sms sender service' do let(:mock_sms) { Barong::MockSMS } before do allow(Barong::App.config).to receive(:twilio_provider).and_return(MockPhoneVerifyService) end context 'when phone is not verified' do let(:phone_number) { build(:phone).number } it 'assigns a phone to account and send sms' do do_request expect_body.to eq(message: 'Code was sent successfully via sms') expect_status.to eq 201 expect(mock_sms.messages.last.to).to eq "+#{phone_number}" end it 'sends a default sms content' do do_request expect_body.to eq(message: 'Code was sent successfully via sms') expect_status.to eq 201 expect(mock_sms.messages.last.body).to start_with('Your verification code for Barong: ') end it 'sends a custom message with content before code' do allow(Barong::App.config).to receive(:sms_content_template).and_return('Please confirm your phone with the following code: {{code}}') do_request expect_body.to eq(message: 'Code was sent successfully via sms') expect_status.to eq 201 expect(mock_sms.messages.last.body).to start_with('Please confirm your phone with the following code: ') end it 'sends a custom message with content after code' do allow(Barong::App.config).to receive(:sms_content_template).and_return('{{code}} - this is your confirmation code') do_request expect_body.to eq(message: 'Code was sent successfully via sms') expect_status.to eq 201 expect(mock_sms.messages.last.body).to end_with(' - this is your confirmation code') end it 'sends a custom message with code in the midle of the content' do allow(Barong::App.config).to receive(:sms_content_template).and_return('Following code: {{code}} should be used for phone confirmation') do_request expect_body.to eq(message: 'Code was sent successfully via sms') expect_status.to eq 201 expect(mock_sms.messages.last.body).to start_with('Following code: ') expect(mock_sms.messages.last.body).to end_with(' should be used for phone confirmation') end end context 'when phone is valid' do let(:phone_number) { build(:phone).number } it 'creates a phone and send sms' do do_request expect_body.to eq(message: 'Code was sent successfully via sms') expect_status.to eq 201 expect(mock_sms.messages.last.to).to eq "+#{phone_number}" end it 'doesnt change code in DB on phone initialize' do do_request expect_body.to eq(message: 'Code was sent successfully via sms') expect_status.to eq 201 code_after_create = Phone.last.code # Phone.last initilazes phone code_after_initialize = Phone.last.code expect(code_after_create).to eq code_after_initialize end end end context 'POST /api/v2/resource/phones/verify' do let(:do_request) do post '/api/v2/resource/phones/verify', params: params, headers: auth_header end let(:params) do { phone_number: phone_number, verification_code: verification_code } end let(:verification_code) { '12345' } context 'when phone is missing and code is missing' do let(:phone_number) { nil } let(:verification_code) { '' } it 'renders an error' do do_request expect_body.to eq(errors: ['resource.phone.empty_phone_number', 'resource.phone.empty_verification_code']) expect_status.to eq 422 end end context 'when phone is invalid' do let(:phone_number) { '123' } it 'renders an error' do do_request expect_body.to eq(errors: ['resource.phone.invalid_num']) expect_status.to eq 400 end end context 'when phone is already exists and verified' do let!(:phone) do create(:phone, validated_at: 1.minutes.ago) end let(:phone_number) { phone.number } it 'renders an error' do do_request expect_body.to eq(errors: ['resource.phone.number_exist']) expect_status.to eq 400 end end context 'when phone exists in international format' do let!(:phone) do create(:phone, validated_at: 1.minutes.ago, number: international_phone) end let(:phone_number) { '+44 07418084106' } let(:international_phone) { '447418084106' } it 'renders an error' do do_request expect_body.to eq(errors: ['resource.phone.number_exist']) expect_status.to eq 400 end end context 'when phone is not found in test_user' do let!(:phone) { create(:phone) } let(:phone_number) { phone.number } it 'rendens an error' do do_request expect_body.to eq(errors: ['resource.phone.doesnt_exist']) expect_status.to eq 404 end end context 'when phone is found in test_user but code is invalid still approves because of mock provider' do let!(:phone) { create(:phone, user: test_user) } let(:phone_number) { phone.number } it 'approves phone' do do_request expect_status.to eq 201 expect(phone.reload.validated_at).to be end end context 'when phone and code is valid' do let(:phone) { create(:phone, user: test_user) } let(:phone_number) { phone.number } let(:verification_code) { phone.code } it 'responses with success' do set_level(test_user, 1) do_request expect_status.to eq 201 expect(phone.reload.validated_at).to be test_user.update_level expect(test_user.reload.level).to eq 2 end end end end end