【发布时间】:2016-12-15 00:16:11
【问题描述】:
概述
我正在开发一个 Ruby on Rails 应用程序,其中一部分使用 Fullcalendar 将事件拖放到日历空间中、日历空间之外和之内,以设置日程安排。
这一切都很好,但测试它是另一回事。最初,我通过模拟通过拖放方法收集的数据的控制器规范测试了该功能,但不幸的是,发现控制器规范破坏了整个测试套件。因此,我不得不使用功能规范对此进行测试,并实际将面板拖放到日历上。
失败的测试尝试 #1
最初,我尝试使用 Capybara 的 Node::Element#drag_to,尽可能地指定一个深入日历的元素(结果是时间槽的 <tr> 元素的第二个 <td> 子元素(例如:@ 987654325@)。
确切的调用是:
这失败了,我很确定它失败了,因为该 <td> 元素的左边缘超出了 Fullcalendar 注册为可放置的区域,因此该元素返回到它的主页。
我想我需要一种方法来指定像素水平偏移来解决这个问题。
失败的测试尝试 #2
Capybara/Poltergeist 附带了一个看似方便的drag_by(x, y)(参见文档here)。因为我需要根据给定的 div 元素计算我自己的 x 和 y 偏移量,所以我在我的规范中将该操作隔离到它自己的函数中:
def drag_to_calendar(element_identifier, time = '12:00:00', x_off = 0, y_off = 0)
x_buff = 100 # Number of pixels to the right of the left edge to get to the middle-area of the element
y_buff = 10 # Number of pixels below the top to get to the middle-area of the element
dest_x_script = "$('tr[data-time=\"#{time}\"]').offset().left"
dest_y_script = "$('tr[data-time=\"#{time}\"]').offset().top"
init_x_script = "$('#{element_identifier}').offset().left"
init_y_script = "$('#{element_identifier}').offset().top"
dest_x = page.evaluate_script(dest_x_script) + x_buff + x_off
dest_y = page.evaluate_script(dest_y_script) + y_buff + y_off
init_x = page.evaluate_script(init_x_script)
init_y = page.evaluate_script(init_y_script)
x = dest_x - init_x
y = dest_y - init_y
find(element_identifier).native.drag_by(x, y)
end
我使函数允许指定任何时间,以及任何额外的 x 和 y 偏移量(用于在日历内/周围更动态地移动元素)。 element_identifier 只是一个字符串,可以直接插入到 Capybara find() 函数中以获取该元素。
示例用法:
drag_to_calendar("div[data-duration="1800000"]", '12:00:00', 0, 0)
(*_script 变量是因为你不能直接将 #{variables} 插入到 evaluate_script 参数中,所以我必须在调用它们之前构建这些字符串。你可能会注意到我只得到了 <tr> 元素在脚本中,而不是第二个 <td> 子元素;那是因为我无法让 .offset() 对子元素起作用;100 像素的水平偏移是为了比以前更左开始)
使用 binding.pry 我确认所有变量都设置正确,所有脚本运行正常,最后所有算术都正常运行。
使用完全基于robertc's answer here 的与应用程序无关的完全独特的测试页面,我确认 Capybara/Poltergeist 的 drab_by 也可以正常工作。 (为了构建测试环境,我用 robertc 的示例覆盖了发生这一切的 #edit 页面,将他的备用样式添加到 application.scss,并将以下代码添加到在该页面上运行的 javascript 文件中:
$(document).on('turbolinks:load',function() {
// Pre-existing javascript things....
dm = document.getElementById('dragme');
if (dm != null) {
dm.addEventListener("mousedown", dmMouseDown, false);
}
});
function dmMouseDown () {
stateMouseDown = true;
document.addEventListener ("mousemove", dmMouseMove, false);
}
function dmMouseMove(ev) {
var pX = ev.pageX;
var pY = ev.pageY;
dm.style.left = pX + "px";
dm.style.top = pY + "px";
document.addEventListener ("mouseup", dmMouseUp, false);
}
function dmMouseUp() {
document.removeEventListener ("mousemove", dmMouseMove, false);
document.removeEventListener ("mouseup", dmMouseUp, false);
}
这表明 Capybara/Poltergeist 的 drag_by 操作与使用鼠标拖动元素完全相同。
然而,当所有这些功能元素结合在一起时,规范仍然无法正常工作。在 binding.pry 环境中,我使用我能想到的每一个变换测试了阻力:使用负值(如果我进入一个镜像宇宙,其中 +x 表示左),将 x 和 y 视为与初始值的偏移量元素,将它们视为页面原点的绝对值,甚至将半随机值扔到 x 和 y 中,希望最终有足够的飞镖可能会击中飞镖板。没有任何效果。要么元素没有被拖动(不太可能,考虑到上述情况),要么 fullcalendar 没有注册放置。
评估
我认为问题出在 Fullcalendar 上,或者在 Poltergeist 和 Fullcalendar 之间的交互中,Fullcalendar 没有将任何东西识别为丢弃。查看 Chrome 调试工具上的事件侦听器,似乎 mousedown、mouseup 和 mousemove 是 Javascript 仅有的与拖放相关的东西,因此是 Fullcalendar 唯一可以寻找的东西,因此 似乎它应该可以工作。但事实并非如此。
任何建议将不胜感激。任何解决方案,更是如此!
【问题讨论】:
标签: javascript ruby-on-rails rspec capybara poltergeist