它比说ERB有点笨拙,但是您可以使用binding
andeval
直接运行 Jbuilder 模板。例如,给定一个引用模型实例的典型Jbuilder
模板:app/views/items/_item.json.jbuilder
item
Item
json.extract! item, :id, :name, :active, :created_at, :updated_at
json.url item_url(item, format: :json)
假设您有一个返回单个Item
对象的端点。在您的请求规范中,您点击了该端点:
get item_url(id: 1), as: :json
expect(response).to be_successful # just to be sure
要获得预期值,您可以按如下方式评估模板:
item = Item.find(1) # local variable `item` needed by template
json = JbuilderTemplate.new(JbuilderHandler) # local variable `json`, ditto
template_path = 'app/views/items/_item.json.jbuilder'
binding.eval(File.read(template_path)) # run the template
# or, for better error messages:
# binding.eval(File.read(template_path), File.basename(template_path))
expected_json = json.target! # template result, as a string
然后,您可以将模板输出与原始 HTTP 响应进行比较:
expect(response.body).to eq(expected_json) # plain string comparison
或者,当然,您可以解析和比较解析后的结果:
actual_value = JSON.parse(response.body)
expected_value = JSON.parse(expected_json)
expect(actual_value).to eq(expected_value)
如果您要经常这样做——或者,例如,如果您希望能够将模板结果与返回的 JSON 数组的各个元素进行比较,您可能需要提取一个方法:
def template_result(template_path, bind)
json = JbuilderTemplate.new(JbuilderHandler)
# `bind` is passed in and doesn't include locals declared here,
# so we need to add `json` explicitly
bind.local_variable_set(:json, json)
bind.eval(File.read(template_path), File.basename(template_path))
JSON.parse(json.target!)
end
然后,您可以执行以下操作:
it 'sorts by name by default' do
get items_url, as: :json
expect(response).to be_successful
parsed_response = JSON.parse(response.body)
expect(parsed_response.size).to eq(Item.count)
expected_items = Item.order(:name)
expected_items.each_with_index do |item, i| # item is used by `binding`
expected_json = template_result('app/views/items/_item.json.jbuilder', binding)
expect(parsed_response[i]).to eq(expected_json)
end
end