[英]How to upload a file in a Rails Rspec request spec
I want to test uploading a file in a Rails Rspec request test.我想在 Rails Rspec 请求测试中测试上传文件。 I'm using Paperclip for asset storage.我正在使用 Paperclip 进行资产存储。
I've tried:我试过了:
path = 'path/to/fixture_file'
params = { file: Rack::Test::UploadedFile.new(path, 'application/pdf', true) }
post v1_product_documents_path, params: params
In the controller, I get a string在 controller 中,我得到一个字符串
"#Rack::Test::UploadedFile:0x0055b544479128>" “#Rack::Test::UploadedFile:0x0055b544479128>”
instead of the actual file.而不是实际的文件。
The same code works in controller tests相同的代码在 controller 测试中有效
try to use fixture_file_upload : fixture_file_upload尝试使用fixture_file_upload : fixture_file_upload
or if you wanted to use this in a factory或者如果您想在工厂中使用它
Rack::Test::UploadedFile.new(File.open(File.join(Rails.root, '/spec/fixtures/images/bob-weir.jpg')))
In rails_helper.rb do在 rails_helper.rb 做
include ActionDispatch::TestProcess
include Rack::Test::Methods
Then you have few options.那么你有几个选择。 1. You can use fixture_file_upload helper 1.你可以使用fixture_file_upload helper
let(:file) { fixture_file_upload('files/image.jpg') }
it 'it should work' do
post some_path, params: { uploads: { file: file } }
end
let(:file) { Rack::Test::UploadedFile.new(Rails.root.join('spec',
'fixtures', 'blank.jpg'), 'image/jpg') }
let(:params) { { attachment: file, variant_ids: ['', product.master.id] } }
let(:action) { post :create, product_id: product.slug, image: params }
Under describe
block, include these modules在describe
块下,包括这些模块
include Rack::Test::Methods
include ActionDispatch::TestProcess
Now try running the specs现在尝试运行规范
path = 'path/to/fixture_file'
params = { "file" => Rack::Test::UploadedFile.new(path, 'application/pdf', true) }
post v1_product_documents_path, params: params
Also, I guess you forgot to add ,
between v1_product_documents_path
and params: params
, please add that and let me know.另外,我想你忘了加,
之间v1_product_documents_path
和params: params
,请补充说明,让我知道。
Hope that helps!希望有帮助!
For rails 6 no need to do includes, just fixture_file_upload
.对于 rails 6 不需要做包含,只需要fixture_file_upload
。 If you are using spec/fixtures/files
folder for fixtures you can use file_fixture
helper如果您使用spec/fixtures/files
夹作为装置,您可以使用file_fixture
helper
let(:csv_file) { fixture_file_upload(file_fixture('file_example.csv')) }
subject(:http_request) { post upload_file_path, params: { file: csv_file } }
可能对其他用户有用:我遇到这个问题是因为我在规范中错误地使用了get
而不是post
请求。
对于其他人在实施上述批准的解决方案后"#Rack::Test::UploadedFile:0x0055b544479128>"
在控制器中获得类似"#Rack::Test::UploadedFile:0x0055b544479128>"
的信息,我通过将content-type
标题更改为'application/x-www-form-urlencoded'
来解决此问题'application/x-www-form-urlencoded'
以便接受表单数据。
file = File.expand_path("path/to/fixture_file", __dir__)
Rack::Test::UploadedFile.new(file, 'application/pdf')
If you need the content type
in your RSpec test, it seems you can pass it as an argument to fixture_file_upload
(no idea why this method does not derive the content type from the OS).如果您在 RSpec 测试中需要content type
,您似乎可以将其作为参数传递给fixture_file_upload
(不知道为什么此方法不从操作系统派生内容类型)。
For instance:例如:
fixture_file_upload("pdfs/some.pdf", "application/pdf")
I ran into this issue while writing request specs for a POST endpoint that processes incoming email payloads that include file attachments.我在为处理包含文件附件的传入 email 有效载荷的 POST 端点编写请求规范时遇到了这个问题。
this is what the request looked like in the request spec:这是请求规范中请求的样子:
post api_v1_email_processor_path, params: params, as: :json
where params[:attachment]
was:其中params[:attachment]
是:
fixture_file_upload("spec/support/fixtures/files/report.csv", 'text/csv',)
and when I added some breakpoints in the controller, this is what the attachment was being converted into:当我在 controller 中添加一些断点时,这就是附件被转换成的内容:
{"original_filename"=>"report.csv", "tempfile"=>"#<File:0x0000000121d2bfc8>", "content_type"=>"text/csv"}
as you can see, the "tempfile"
was being cast to a string value of "<File:0x0000000121d2bfc8>"
如您所见, "tempfile"
被转换为字符串值"<File:0x0000000121d2bfc8>"
when I emulated the same request in a controller spec, to my huge confusion, there was no casting, and the breakpoint showed the param (correctly) as:当我在controller规范中模拟相同的请求时,令我非常困惑的是,没有强制转换,断点将参数(正确地)显示为:
#<ActionDispatch::Http::UploadedFile:0x000000012d559488 @tempfile=#<Tempfile:/var/folders/jg/n_0rknb97kvddb0jgh6r3_x40000gn/T/RackMultipart20221008-45122-mzyqg5.csv>, @original_filename="report.csv", @content_type="text/csv", @headers="Content-Disposition: form-data; name=\"attachment1\"; filename=\"report.csv\"\r\nContent-Type: text/csv\r\nContent-Length: 24931\r\n">]
after seeing L.Youl's answer https://stackoverflow.com/a/67987482/14926068 , it got me thinking that the issue was with how the request payload was being formatted, prior to being sent to the server through the Rack middleware.在看到 L.Youl 的回答https://stackoverflow.com/a/67987482/14926068后,我开始思考问题出在请求有效负载在通过 Rack 中间件发送到服务器之前如何格式化。 and so I tried taking off the as: :json
:所以我试着取消as: :json
:
post api_v1_email_processor_path, params: params
and bingo, I got the same result as with the controller spec.和宾果游戏,我得到了与 controller 规范相同的结果。
after inspecting response.request.content_type
in my request spec, I found that when I took the as: :json
off, its value changed from "application/json"
to在我的请求规范中检查response.request.content_type
后,我发现当我关闭as: :json
时,它的值从"application/json"
变为
"multipart/form-data; boundary=----------XnJLe9ZIbbGUYtzPQJ16u1"
for completeness, I checked response.request.content_type
in the controller spec as well, and found that even with as: :json
in the request, the content_type
was being set to "multipart/form-data"
, and that accounted for the discrepancy in behavior between controller and request specs - it seems that as: :json
only affects the "content-type"
in the request specs.为了完整起见,我还检查了 controller 规范中的response.request.content_type
,发现即使在请求中使用as: :json
, content_type
也被设置为"multipart/form-data"
,这就是差异的原因在 controller 和请求规范之间的行为中 - 似乎as: :json
只影响请求规范中的"content-type"
。
in retrospect, it was obvious - json cannot be used to send actual files.回想起来,很明显 - json 不能用于发送实际文件。 but it took me a long time to figure it out because the equivalent controller spec was working fine and this was literally the only endpoint in my Rails api-only app that expected non-json payloads但我花了很长时间才弄明白,因为等效的 controller 规范工作正常,这实际上是我的 Rails api-only 应用程序中唯一预期非 json 有效载荷的端点
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.