Обзор
Я работаю над приложением Ruby on Rails, часть которого использует Fullcalendar для перетаскивания и упорядочивания событий в пространстве календаря, вне его и внутри пространства календаря для настройки дневного расписания.
Это все прекрасно работает, но проверить это — другое дело. Первоначально я тестировал функциональность с помощью спецификации контроллера, которая эмулировала данные, собранные с помощью методов перетаскивания, но, к сожалению, было обнаружено, что спецификации контроллера нарушают весь набор тестов. Таким образом, я вынужден тестировать это с помощью спецификаций функций и фактически перетаскивать панели в календарь.
Неудачная попытка тестирования №1
Сначала я попытался использовать Node::Element#drag_to Capybara, указав элемент как можно глубже в календаре (который оказался вторым <td>
дочерним элементом <tr>
элемента временного интервала (пример: $('tr[data-time="12:00:00"] td.fc-widget-content')[1]
).
Точный звонок был:
find('div[data-duration="1800000"]').drag_to all('tr[data-time="12:00:00"] td.fc-widget-content')[1]
find
находил правильный элемент, как и all
, как было проверено с помощью binding.pry
Это не удается, и я почти уверен, что это не удается, потому что левый край этого элемента <td>
находится за пределами области, которую Fullcalendar регистрирует как удаляемую, и, таким образом, элемент возвращается на свое место.
Я подумал, что мне нужен способ указать смещение по горизонтали в пикселях, чтобы обойти эту проблему.
Неудачная попытка тестирования № 2
Capybara/Poltergeist поставляется с, казалось бы, удобным drag_by(x, y)
(см. документацию здесь а>). Поскольку мне нужно было вычислить свои собственные смещения x и y из заданных элементов div, я выделил эту операцию в отдельную функцию в своих спецификациях:
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} в аргументы Assessment_script, поэтому мне пришлось создавать эти строки перед их вызовом. Вы могли заметить, что вместо этого я получаю только элементы <tr>
в сценариях. второго <td>
дочернего элемента; это потому, что я не мог заставить .offset() работать с дочерними элементами; 100-пиксельное смещение по горизонтали должно было начинаться дальше влево, чем раньше)
С помощью binding.pry я убедился, что все переменные заданы правильно, все скрипты работают правильно, а все арифметические операции в конце работают как надо.
Использование совершенно уникальной тестовой страницы, не связанной с приложением, в значительной степени основанной на ответ robertc здесь Я подтвердил, что drab_by Капибары/Полтергейста также работает. (Для создания тестовой среды я перезаписал страницу #edit, на которой все это происходит, примером robertc, добавил его стиль aside в 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);
}
Это показало, что drag_by Capybara/Poltergeist работает точно так же, как перетаскивание элемента с помощью мыши.
И все же, когда все эти функционирующие элементы собрались вместе, спецификация все еще не функционировала. В среде binding.pry я тестировал перетаскивание, используя все возможные преобразования: перестановку x и y, использование отрицательных значений (на случай, если я попал в зеркальную вселенную, где +x означает, что осталось), обработку x и y как смещения от начального element, рассматривая их как абсолютные из источника страницы и даже подбрасывая полуслучайные значения в x и y в надежде, что достаточное количество дротиков может в конечном итоге попасть в мишень для дротиков. Ничего не сработало. Либо элементы не перетаскиваются (маловероятно, учитывая вышеизложенное), либо fullcalendar не регистрирует перетаскивание.
Оценка
Я думаю, что проблема связана с Fullcalendar или во взаимодействии между Poltergeist и Fullcalendar, когда Fullcalendar ничего не распознает как отбрасываемое. Просматривая прослушиватели событий в инструментах отладки Chrome, кажется, что mousedown, mouseup и mousemove — единственные связанные с перетаскиванием вещи, которые есть в Javascript, и, следовательно, это единственные вещи, которые Fullcalendar мог бы искать, и таким образом< /em> кажется, это должно работать. Но это не так.
Любые советы будут высоко ценится. Любые решения, тем более!