use webhook urls instead of encrypted configs
This commit is contained in:
committed by
Pete Matsyburka
parent
f669045362
commit
84edb6dbda
@@ -0,0 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :webhook_url do
|
||||
account
|
||||
url { Faker::Internet.url }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,108 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SendFormCompletedWebhookRequestJob do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account:) }
|
||||
let(:template) { create(:template, account:, author: user) }
|
||||
let(:submission) { create(:submission, template:, created_by_user: user) }
|
||||
let(:submitter) do
|
||||
create(:submitter, submission:, uuid: template.submitters.first['uuid'], completed_at: Time.current)
|
||||
end
|
||||
let(:webhook_url) { create(:webhook_url, account:, events: ['form.completed']) }
|
||||
|
||||
before do
|
||||
create(:encrypted_config, key: EncryptedConfig::ESIGN_CERTS_KEY,
|
||||
value: GenerateCertificate.call.transform_values(&:to_pem))
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'sends a webhook request' do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'form.completed',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Submitters::SerializeForWebhook.call(submitter.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it 'sends a webhook request with the secret' do
|
||||
webhook_url.update(secret: { 'X-Secret-Header' => 'secret_value' })
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'form.completed',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Submitters::SerializeForWebhook.call(submitter.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook',
|
||||
'X-Secret-Header' => 'secret_value'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the submitter doesn't exist" do
|
||||
expect do
|
||||
described_class.new.perform('submitter_id' => 100_500, 'webhook_url_id' => webhook_url.id)
|
||||
end.to raise_error ActiveRecord::RecordNotFound
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the event is not in the webhook's events" do
|
||||
webhook_url.update!(events: ['form.declined'])
|
||||
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the webhook doesn't exist" do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => 100_500)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it 'sends again if the response status is 400 or higher' do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
end.to change(described_class.jobs, :size).by(1)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
|
||||
args = described_class.jobs.last['args'].first
|
||||
|
||||
expect(args['attempt']).to eq(1)
|
||||
expect(args['last_status']).to eq(401)
|
||||
expect(args['webhook_url_id']).to eq(webhook_url.id)
|
||||
expect(args['submitter_id']).to eq(submitter.id)
|
||||
end
|
||||
|
||||
it "doesn't send again if the max attempts is reached" do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id, 'attempt' => 11)
|
||||
end.not_to change(described_class.jobs, :size)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,108 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SendFormDeclinedWebhookRequestJob do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account:) }
|
||||
let(:template) { create(:template, account:, author: user) }
|
||||
let(:submission) { create(:submission, template:, created_by_user: user) }
|
||||
let(:submitter) do
|
||||
create(:submitter, submission:, uuid: template.submitters.first['uuid'], completed_at: Time.current)
|
||||
end
|
||||
let(:webhook_url) { create(:webhook_url, account:, events: ['form.declined']) }
|
||||
|
||||
before do
|
||||
create(:encrypted_config, key: EncryptedConfig::ESIGN_CERTS_KEY,
|
||||
value: GenerateCertificate.call.transform_values(&:to_pem))
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'sends a webhook request' do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'form.declined',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Submitters::SerializeForWebhook.call(submitter.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it 'sends a webhook request with the secret' do
|
||||
webhook_url.update(secret: { 'X-Secret-Header' => 'secret_value' })
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'form.declined',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Submitters::SerializeForWebhook.call(submitter.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook',
|
||||
'X-Secret-Header' => 'secret_value'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the submitter doesn't exist" do
|
||||
expect do
|
||||
described_class.new.perform('submitter_id' => 100_500, 'webhook_url_id' => webhook_url.id)
|
||||
end.to raise_error ActiveRecord::RecordNotFound
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the event is not in the webhook's events" do
|
||||
webhook_url.update!(events: ['form.completed'])
|
||||
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the webhook doesn't exist" do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => 100_500)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it 'sends again if the response status is 400 or higher' do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
end.to change(described_class.jobs, :size).by(1)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
|
||||
args = described_class.jobs.last['args'].first
|
||||
|
||||
expect(args['attempt']).to eq(1)
|
||||
expect(args['last_status']).to eq(401)
|
||||
expect(args['webhook_url_id']).to eq(webhook_url.id)
|
||||
expect(args['submitter_id']).to eq(submitter.id)
|
||||
end
|
||||
|
||||
it "doesn't send again if the max attempts is reached" do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id, 'attempt' => 11)
|
||||
end.not_to change(described_class.jobs, :size)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,108 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SendFormStartedWebhookRequestJob do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account:) }
|
||||
let(:template) { create(:template, account:, author: user) }
|
||||
let(:submission) { create(:submission, template:, created_by_user: user) }
|
||||
let(:submitter) do
|
||||
create(:submitter, submission:, uuid: template.submitters.first['uuid'], completed_at: Time.current)
|
||||
end
|
||||
let(:webhook_url) { create(:webhook_url, account:, events: ['form.started']) }
|
||||
|
||||
before do
|
||||
create(:encrypted_config, key: EncryptedConfig::ESIGN_CERTS_KEY,
|
||||
value: GenerateCertificate.call.transform_values(&:to_pem))
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'sends a webhook request' do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'form.started',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Submitters::SerializeForWebhook.call(submitter.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it 'sends a webhook request with the secret' do
|
||||
webhook_url.update(secret: { 'X-Secret-Header' => 'secret_value' })
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'form.started',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Submitters::SerializeForWebhook.call(submitter.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook',
|
||||
'X-Secret-Header' => 'secret_value'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the submitter doesn't exist" do
|
||||
expect do
|
||||
described_class.new.perform('submitter_id' => 100_500, 'webhook_url_id' => webhook_url.id)
|
||||
end.to raise_error ActiveRecord::RecordNotFound
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the event is not in the webhook's events" do
|
||||
webhook_url.update!(events: ['form.declined'])
|
||||
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the webhook doesn't exist" do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => 100_500)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it 'sends again if the response status is 400 or higher' do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
end.to change(described_class.jobs, :size).by(1)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
|
||||
args = described_class.jobs.last['args'].first
|
||||
|
||||
expect(args['attempt']).to eq(1)
|
||||
expect(args['last_status']).to eq(401)
|
||||
expect(args['webhook_url_id']).to eq(webhook_url.id)
|
||||
expect(args['submitter_id']).to eq(submitter.id)
|
||||
end
|
||||
|
||||
it "doesn't send again if the max attempts is reached" do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id, 'attempt' => 11)
|
||||
end.not_to change(described_class.jobs, :size)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,108 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SendFormViewedWebhookRequestJob do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account:) }
|
||||
let(:template) { create(:template, account:, author: user) }
|
||||
let(:submission) { create(:submission, template:, created_by_user: user) }
|
||||
let(:submitter) do
|
||||
create(:submitter, submission:, uuid: template.submitters.first['uuid'], completed_at: Time.current)
|
||||
end
|
||||
let(:webhook_url) { create(:webhook_url, account:, events: ['form.viewed']) }
|
||||
|
||||
before do
|
||||
create(:encrypted_config, key: EncryptedConfig::ESIGN_CERTS_KEY,
|
||||
value: GenerateCertificate.call.transform_values(&:to_pem))
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'sends a webhook request' do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'form.viewed',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Submitters::SerializeForWebhook.call(submitter.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it 'sends a webhook request with the secret' do
|
||||
webhook_url.update(secret: { 'X-Secret-Header' => 'secret_value' })
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'form.viewed',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Submitters::SerializeForWebhook.call(submitter.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook',
|
||||
'X-Secret-Header' => 'secret_value'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the submitter doesn't exist" do
|
||||
expect do
|
||||
described_class.new.perform('submitter_id' => 100_500, 'webhook_url_id' => webhook_url.id)
|
||||
end.to raise_error ActiveRecord::RecordNotFound
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the event is not in the webhook's events" do
|
||||
webhook_url.update!(events: ['form.started'])
|
||||
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the webhook doesn't exist" do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => 100_500)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it 'sends again if the response status is 400 or higher' do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id)
|
||||
end.to change(described_class.jobs, :size).by(1)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
|
||||
args = described_class.jobs.last['args'].first
|
||||
|
||||
expect(args['attempt']).to eq(1)
|
||||
expect(args['last_status']).to eq(401)
|
||||
expect(args['webhook_url_id']).to eq(webhook_url.id)
|
||||
expect(args['submitter_id']).to eq(submitter.id)
|
||||
end
|
||||
|
||||
it "doesn't send again if the max attempts is reached" do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submitter_id' => submitter.id, 'webhook_url_id' => webhook_url.id, 'attempt' => 11)
|
||||
end.not_to change(described_class.jobs, :size)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,106 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SendSubmissionArchivedWebhookRequestJob do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account:) }
|
||||
let(:template) { create(:template, account:, author: user) }
|
||||
let(:submission) { create(:submission, template:, created_by_user: user) }
|
||||
let(:webhook_url) { create(:webhook_url, account:, events: ['submission.archived']) }
|
||||
|
||||
before do
|
||||
create(:encrypted_config, key: EncryptedConfig::ESIGN_CERTS_KEY,
|
||||
value: GenerateCertificate.call.transform_values(&:to_pem))
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'sends a webhook request' do
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'submission.archived',
|
||||
'timestamp' => Time.current,
|
||||
'data' => submission.reload.as_json(only: %i[id archived_at])
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it 'sends a webhook request with the secret' do
|
||||
webhook_url.update(secret: { 'X-Secret-Header' => 'secret_value' })
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'submission.archived',
|
||||
'timestamp' => Time.current,
|
||||
'data' => submission.reload.as_json(only: %i[id archived_at])
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook',
|
||||
'X-Secret-Header' => 'secret_value'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the submission doesn't exist" do
|
||||
expect do
|
||||
described_class.new.perform('submission_id' => 100_500, 'webhook_url_id' => webhook_url.id)
|
||||
end.to raise_error ActiveRecord::RecordNotFound
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the event is not in the webhook's events" do
|
||||
webhook_url.update!(events: ['submission.created'])
|
||||
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the webhook doesn't exist" do
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => 100_500)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it 'sends again if the response status is 400 or higher' do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id)
|
||||
end.to change(described_class.jobs, :size).by(1)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
|
||||
args = described_class.jobs.last['args'].first
|
||||
|
||||
expect(args['attempt']).to eq(1)
|
||||
expect(args['last_status']).to eq(401)
|
||||
expect(args['webhook_url_id']).to eq(webhook_url.id)
|
||||
expect(args['submission_id']).to eq(submission.id)
|
||||
end
|
||||
|
||||
it "doesn't send again if the max attempts is reached" do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id,
|
||||
'attempt' => 11)
|
||||
end.not_to change(described_class.jobs, :size)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,106 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SendSubmissionCompletedWebhookRequestJob do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account:) }
|
||||
let(:template) { create(:template, account:, author: user) }
|
||||
let(:submission) { create(:submission, :with_submitters, template:, created_by_user: user) }
|
||||
let(:webhook_url) { create(:webhook_url, account:, events: ['submission.completed']) }
|
||||
|
||||
before do
|
||||
create(:encrypted_config, key: EncryptedConfig::ESIGN_CERTS_KEY,
|
||||
value: GenerateCertificate.call.transform_values(&:to_pem))
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'sends a webhook request' do
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'submission.completed',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Submissions::SerializeForApi.call(submission.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it 'sends a webhook request with the secret' do
|
||||
webhook_url.update(secret: { 'X-Secret-Header' => 'secret_value' })
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'submission.completed',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Submissions::SerializeForApi.call(submission.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook',
|
||||
'X-Secret-Header' => 'secret_value'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the submission doesn't exist" do
|
||||
expect do
|
||||
described_class.new.perform('submission_id' => 100_500, 'webhook_url_id' => webhook_url.id)
|
||||
end.to raise_error ActiveRecord::RecordNotFound
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the event is not in the webhook's events" do
|
||||
webhook_url.update!(events: ['submission.archived'])
|
||||
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the webhook doesn't exist" do
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => 100_500)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it 'sends again if the response status is 400 or higher' do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id)
|
||||
end.to change(described_class.jobs, :size).by(1)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
|
||||
args = described_class.jobs.last['args'].first
|
||||
|
||||
expect(args['attempt']).to eq(1)
|
||||
expect(args['last_status']).to eq(401)
|
||||
expect(args['webhook_url_id']).to eq(webhook_url.id)
|
||||
expect(args['submission_id']).to eq(submission.id)
|
||||
end
|
||||
|
||||
it "doesn't send again if the max attempts is reached" do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id,
|
||||
'attempt' => 11)
|
||||
end.not_to change(described_class.jobs, :size)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,106 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SendSubmissionCreatedWebhookRequestJob do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account:) }
|
||||
let(:template) { create(:template, account:, author: user) }
|
||||
let(:submission) { create(:submission, :with_submitters, template:, created_by_user: user) }
|
||||
let(:webhook_url) { create(:webhook_url, account:, events: ['submission.created']) }
|
||||
|
||||
before do
|
||||
create(:encrypted_config, key: EncryptedConfig::ESIGN_CERTS_KEY,
|
||||
value: GenerateCertificate.call.transform_values(&:to_pem))
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'sends a webhook request' do
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'submission.created',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Submissions::SerializeForApi.call(submission.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it 'sends a webhook request with the secret' do
|
||||
webhook_url.update(secret: { 'X-Secret-Header' => 'secret_value' })
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'submission.created',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Submissions::SerializeForApi.call(submission.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook',
|
||||
'X-Secret-Header' => 'secret_value'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the submission doesn't exist" do
|
||||
expect do
|
||||
described_class.new.perform('submission_id' => 100_500, 'webhook_url_id' => webhook_url.id)
|
||||
end.to raise_error ActiveRecord::RecordNotFound
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the event is not in the webhook's events" do
|
||||
webhook_url.update!(events: ['submission.completed'])
|
||||
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the webhook doesn't exist" do
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => 100_500)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it 'sends again if the response status is 400 or higher' do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id)
|
||||
end.to change(described_class.jobs, :size).by(1)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
|
||||
args = described_class.jobs.last['args'].first
|
||||
|
||||
expect(args['attempt']).to eq(1)
|
||||
expect(args['last_status']).to eq(401)
|
||||
expect(args['webhook_url_id']).to eq(webhook_url.id)
|
||||
expect(args['submission_id']).to eq(submission.id)
|
||||
end
|
||||
|
||||
it "doesn't send again if the max attempts is reached" do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('submission_id' => submission.id, 'webhook_url_id' => webhook_url.id,
|
||||
'attempt' => 11)
|
||||
end.not_to change(described_class.jobs, :size)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,104 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SendTemplateCreatedWebhookRequestJob do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account:) }
|
||||
let(:template) { create(:template, account:, author: user) }
|
||||
let(:webhook_url) { create(:webhook_url, account:, events: ['template.created']) }
|
||||
|
||||
before do
|
||||
create(:encrypted_config, key: EncryptedConfig::ESIGN_CERTS_KEY,
|
||||
value: GenerateCertificate.call.transform_values(&:to_pem))
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'sends a webhook request' do
|
||||
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'template.created',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Templates::SerializeForApi.call(template.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it 'sends a webhook request with the secret' do
|
||||
webhook_url.update(secret: { 'X-Secret-Header' => 'secret_value' })
|
||||
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'template.created',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Templates::SerializeForApi.call(template.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook',
|
||||
'X-Secret-Header' => 'secret_value'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the template doesn't exist" do
|
||||
expect do
|
||||
described_class.new.perform('template_id' => 100_500, 'webhook_url_id' => webhook_url.id)
|
||||
end.to raise_error ActiveRecord::RecordNotFound
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the event is not in the webhook's events" do
|
||||
webhook_url.update!(events: ['template.updated'])
|
||||
|
||||
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the webhook doesn't exist" do
|
||||
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => 100_500)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it 'sends again if the response status is 400 or higher' do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
|
||||
end.to change(described_class.jobs, :size).by(1)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
|
||||
args = described_class.jobs.last['args'].first
|
||||
|
||||
expect(args['attempt']).to eq(1)
|
||||
expect(args['last_status']).to eq(401)
|
||||
expect(args['webhook_url_id']).to eq(webhook_url.id)
|
||||
expect(args['template_id']).to eq(template.id)
|
||||
end
|
||||
|
||||
it "doesn't send again if the max attempts is reached" do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id, 'attempt' => 11)
|
||||
end.not_to change(described_class.jobs, :size)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,104 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SendTemplateUpdatedWebhookRequestJob do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account:) }
|
||||
let(:template) { create(:template, account:, author: user) }
|
||||
let(:webhook_url) { create(:webhook_url, account:, events: ['template.updated']) }
|
||||
|
||||
before do
|
||||
create(:encrypted_config, key: EncryptedConfig::ESIGN_CERTS_KEY,
|
||||
value: GenerateCertificate.call.transform_values(&:to_pem))
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 200)
|
||||
end
|
||||
|
||||
it 'sends a webhook request' do
|
||||
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'template.updated',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Templates::SerializeForApi.call(template.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it 'sends a webhook request with the secret' do
|
||||
webhook_url.update(secret: { 'X-Secret-Header' => 'secret_value' })
|
||||
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).with(
|
||||
body: replace_timestamps({
|
||||
'event_type' => 'template.updated',
|
||||
'timestamp' => Time.current,
|
||||
'data' => Templates::SerializeForApi.call(template.reload)
|
||||
}.deep_stringify_keys),
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'DocuSeal.co Webhook',
|
||||
'X-Secret-Header' => 'secret_value'
|
||||
}
|
||||
).once
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the template doesn't exist" do
|
||||
expect do
|
||||
described_class.new.perform('template_id' => 100_500, 'webhook_url_id' => webhook_url.id)
|
||||
end.to raise_error ActiveRecord::RecordNotFound
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the event is not in the webhook's events" do
|
||||
webhook_url.update!(events: ['template.created'])
|
||||
|
||||
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it "doesn't send a webhook request if the webhook doesn't exist" do
|
||||
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => 100_500)
|
||||
|
||||
expect(WebMock).not_to have_requested(:post, webhook_url.url)
|
||||
end
|
||||
|
||||
it 'sends again if the response status is 400 or higher' do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id)
|
||||
end.to change(described_class.jobs, :size).by(1)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
|
||||
args = described_class.jobs.last['args'].first
|
||||
|
||||
expect(args['attempt']).to eq(1)
|
||||
expect(args['last_status']).to eq(401)
|
||||
expect(args['webhook_url_id']).to eq(webhook_url.id)
|
||||
expect(args['template_id']).to eq(template.id)
|
||||
end
|
||||
|
||||
it "doesn't send again if the max attempts is reached" do
|
||||
stub_request(:post, webhook_url.url).to_return(status: 401)
|
||||
|
||||
expect do
|
||||
described_class.new.perform('template_id' => template.id, 'webhook_url_id' => webhook_url.id, 'attempt' => 11)
|
||||
end.not_to change(described_class.jobs, :size)
|
||||
|
||||
expect(WebMock).to have_requested(:post, webhook_url.url).once
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -67,3 +67,19 @@ RSpec.configure do |config|
|
||||
Sidekiq::Testing.inline! if example.metadata[:sidekiq] == :inline
|
||||
end
|
||||
end
|
||||
|
||||
def replace_timestamps(data, replace = /.*/)
|
||||
timestamp_fields = %w[created_at updated_at completed_at sent_at opened_at timestamp]
|
||||
|
||||
data.each do |key, value|
|
||||
if timestamp_fields.include?(key) && (value.is_a?(String) || value.is_a?(Time))
|
||||
data[key] = replace
|
||||
elsif value.is_a?(Hash)
|
||||
replace_timestamps(value)
|
||||
elsif value.is_a?(Array)
|
||||
value.each { |item| replace_timestamps(item) if item.is_a?(Hash) }
|
||||
end
|
||||
end
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
@@ -8,24 +8,110 @@ RSpec.describe 'Webhook Settings' do
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
visit settings_webhooks_path
|
||||
end
|
||||
|
||||
it 'shows webhook settings page' do
|
||||
visit settings_webhooks_path
|
||||
|
||||
expect(page).to have_content('Webhooks')
|
||||
expect(page).to have_field('Webhook URL')
|
||||
expect(page).to have_button('Save')
|
||||
|
||||
WebhookUrl::EVENTS.each do |event|
|
||||
expect(page).to have_field(event, type: 'checkbox', disabled: true)
|
||||
end
|
||||
end
|
||||
|
||||
it 'updates the webhook URL' do
|
||||
fill_in 'Webhook URL', with: 'https://example.com'
|
||||
it 'creates the webhook' do
|
||||
visit settings_webhooks_path
|
||||
|
||||
fill_in 'Webhook URL', with: 'https://example.com/webhook'
|
||||
|
||||
expect do
|
||||
click_button 'Save'
|
||||
end.to change(EncryptedConfig, :count).by(1)
|
||||
end.to change(WebhookUrl, :count).by(1)
|
||||
|
||||
encrypted_config = EncryptedConfig.find_by(account:, key: EncryptedConfig::WEBHOOK_URL_KEY)
|
||||
webhook_url = account.webhook_urls.first
|
||||
|
||||
expect(encrypted_config.value).to eq('https://example.com')
|
||||
expect(webhook_url.url).to eq('https://example.com/webhook')
|
||||
end
|
||||
|
||||
it 'updates the webhook' do
|
||||
webhook_url = create(:webhook_url, account:, url: 'https://example.com/webhook')
|
||||
|
||||
visit settings_webhooks_path
|
||||
|
||||
fill_in 'Webhook URL', with: 'https://example.org/webhook'
|
||||
click_button 'Save'
|
||||
|
||||
webhook_url.reload
|
||||
|
||||
expect(webhook_url.url).to eq('https://example.org/webhook')
|
||||
end
|
||||
|
||||
it 'deletes the webhook' do
|
||||
create(:webhook_url, account:)
|
||||
|
||||
visit settings_webhooks_path
|
||||
|
||||
fill_in 'Webhook URL', with: ''
|
||||
|
||||
expect do
|
||||
click_button 'Save'
|
||||
end.to change(WebhookUrl, :count).by(-1)
|
||||
end
|
||||
|
||||
it 'updates the webhook events' do
|
||||
webhook_url = create(:webhook_url, account:)
|
||||
|
||||
visit settings_webhooks_path
|
||||
|
||||
expect(webhook_url.events).not_to include('submission.created')
|
||||
|
||||
check('submission.created')
|
||||
|
||||
webhook_url.reload
|
||||
|
||||
expect(webhook_url.events).to include('submission.created')
|
||||
end
|
||||
|
||||
it 'adds a secret to the webhook' do
|
||||
webhook_url = create(:webhook_url, account:)
|
||||
|
||||
visit settings_webhooks_path
|
||||
|
||||
expect(webhook_url.secret).to be_nil
|
||||
|
||||
click_link 'Add Secret'
|
||||
|
||||
within '#modal' do
|
||||
fill_in 'Key', with: 'X-Signature'
|
||||
fill_in 'Value', with: 'secret-value'
|
||||
|
||||
click_button 'Submit'
|
||||
|
||||
webhook_url.reload
|
||||
|
||||
expect(webhook_url.secret).to eq({ 'X-Signature' => 'secret-value' })
|
||||
end
|
||||
end
|
||||
|
||||
it 'removes a secret from the webhook' do
|
||||
webhook_url = create(:webhook_url, account:, secret: { 'X-Signature' => 'secret-value' })
|
||||
|
||||
visit settings_webhooks_path
|
||||
|
||||
click_link 'Edit Secret'
|
||||
|
||||
within '#modal' do
|
||||
fill_in 'Key', with: ''
|
||||
fill_in 'Value', with: ''
|
||||
|
||||
click_button 'Submit'
|
||||
|
||||
webhook_url.reload
|
||||
|
||||
expect(webhook_url.secret).to eq({})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user