Edit views in my application provide expected data fields, and also extra fields that do not belong to the model, such as annotations and translations, which are processed by the controller method before saving the edited record.
When writing requests tests, I need to provide these extra fields to the Post method, in addition to the model fields:
RSpec.describe "Playgrounds", type: :request do
include Warden::Test::Helpers
# Playground. As you add validations to Playground, be sure to
# adjust the attributes here as well.
let(:user) { create(:user, is_admin: true) }
let(:playground) {FactoryBot.create(:playground)}
# User login
before do
login_as user, scope: :user
end
describe "POST /playgrounds" do
context "with valid attributes" do
# Use per context let instead
let(:attributes) { attributes_for(:playground) }
it "creates a playground" do
expect {
post '/entities', params: {
playground: attributes,
playground_name_fr: "Donnée de test",
playground_name_de: "",
playground_name_en: "Test data",
playground_name_it: "Dati del test",
playground_description_fr: "Ceci n'est qu'un test",
playground_description_de: "",
playground_description_en: "This is just a test",
playground_description_it: "Questo è solo un test"
}
}.to change(Playground, :count).by(1)
expect(response).to have_http_status 302
end
end
end
end
In order to define these 8 fields used for translation only once, I would like to define a Hash variable, and add it to the playground Hash:
RSpec.describe "Playgrounds", type: :request do
include Warden::Test::Helpers
# Playground. As you add validations to Playground, be sure to
# adjust the attributes here as well.
let(:user) { create(:user, is_admin: true) }
let(:playground) {FactoryBot.create(:playground)}
let(:fields) do
{
playground_name_fr: "Donnée de test",
playground_name_de: "",
playground_name_en: "Test data",
playground_name_it: "Dati del test",
playground_description_fr: "Ceci n'est qu'un test",
playground_description_de: "",
playground_description_en: "This is just a test",
playground_description_it: "Questo è solo un test"
}
end
# User login
before do
login_as user, scope: :user
end
describe "POST /playgrounds" do
context "with valid attributes" do
# Use per context let instead
let(:attributes) { attributes_for(:playground) }
it "creates a playground" do
expect {
post '/entities', params: {
playground: attributes < fields
}
}.to change(Playground, :count).by(1)
expect(response).to have_http_status 302
end
end
end
end
But then I get the following error:
Failure/Error:
params.require(:playground)
.permit(:code,
:status_id,
:logo,
:organisation_id,
:responsible_id,
:deputy_id,
:sort_code,
name: {},
description: {}
NoMethodError:
undefined method `permit' for "false":String
As the first syntax works as expected, and the second does not, I probably inserted the fields at the wrong place or level, but I can't find out how to solve this?
Thank you for your help!
The issue was to reproduce the params hash expected by the controller under test. Beside some tokens, params contains:
Example:
<ActionController::Parameters {"utf8"=>"✓",
"authenticity_token"=>"uJysIqrglzyBSAx9O49TRZ4NfggMw9C59/w==",
"playground"=><ActionController::Parameters {
"code"=>"TESTB",
"sort_code"=>"",
"organisation_id"=>"0",
"responsible_id"=>"1",
"deputy_id"=>"2"} permitted: false>,
"playground_name_fr"=>"Société test",
"playground_name_de"=>"Data governance",
"playground_name_en"=>"TESTBC",
"playground_name_it"=>"Società di test",
"playground_description_fr"=>"",
"playground_description_de"=>"",
"playground_description_en"=>"",
"playground_description_it"=>"",
"controller"=>"playgrounds",
"action"=>"create"} permitted: false>
Then the solution is to add fields hash to the params hash itself:
expect {
post '/entities', params: {
playground: attributes
}.merge(fields)
}.to change(Playground, :count).by(1)
Thanks a lot Max and Eugen for putting me on the way!