Merge branch 'refactor_simulate_drag' into 'master'
Refactor test_utils bundle See merge request !10437
This commit is contained in:
commit
0a4b853f2c
13 changed files with 147 additions and 153 deletions
|
@ -8,6 +8,7 @@ cache:
|
||||||
variables:
|
variables:
|
||||||
MYSQL_ALLOW_EMPTY_PASSWORD: "1"
|
MYSQL_ALLOW_EMPTY_PASSWORD: "1"
|
||||||
RAILS_ENV: "test"
|
RAILS_ENV: "test"
|
||||||
|
NODE_ENV: "test"
|
||||||
SIMPLECOV: "true"
|
SIMPLECOV: "true"
|
||||||
SETUP_DB: "true"
|
SETUP_DB: "true"
|
||||||
USE_BUNDLE_INSTALL: "true"
|
USE_BUNDLE_INSTALL: "true"
|
||||||
|
@ -129,9 +130,7 @@ setup-test-env:
|
||||||
stage: prepare
|
stage: prepare
|
||||||
script:
|
script:
|
||||||
- node --version
|
- node --version
|
||||||
- yarn --version
|
|
||||||
- yarn install --pure-lockfile
|
- yarn install --pure-lockfile
|
||||||
- yarn check # ensure that yarn.lock matches package.json
|
|
||||||
- bundle exec rake gitlab:assets:compile
|
- bundle exec rake gitlab:assets:compile
|
||||||
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
|
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
|
||||||
artifacts:
|
artifacts:
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -223,7 +223,7 @@ gem 'oj', '~> 2.17.4'
|
||||||
gem 'chronic', '~> 0.10.2'
|
gem 'chronic', '~> 0.10.2'
|
||||||
gem 'chronic_duration', '~> 0.10.6'
|
gem 'chronic_duration', '~> 0.10.6'
|
||||||
|
|
||||||
gem 'webpack-rails', '~> 0.9.9'
|
gem 'webpack-rails', '~> 0.9.10'
|
||||||
gem 'rack-proxy', '~> 0.6.0'
|
gem 'rack-proxy', '~> 0.6.0'
|
||||||
|
|
||||||
gem 'sass-rails', '~> 5.0.6'
|
gem 'sass-rails', '~> 5.0.6'
|
||||||
|
|
|
@ -823,8 +823,8 @@ GEM
|
||||||
addressable (>= 2.3.6)
|
addressable (>= 2.3.6)
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
hashdiff
|
hashdiff
|
||||||
webpack-rails (0.9.9)
|
webpack-rails (0.9.10)
|
||||||
rails (>= 3.2.0)
|
railties (>= 3.2.0)
|
||||||
websocket-driver (0.6.3)
|
websocket-driver (0.6.3)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.2)
|
websocket-extensions (0.1.2)
|
||||||
|
@ -1026,7 +1026,7 @@ DEPENDENCIES
|
||||||
virtus (~> 1.0.1)
|
virtus (~> 1.0.1)
|
||||||
vmstat (~> 2.3.0)
|
vmstat (~> 2.3.0)
|
||||||
webmock (~> 1.24.0)
|
webmock (~> 1.24.0)
|
||||||
webpack-rails (~> 0.9.9)
|
webpack-rails (~> 0.9.10)
|
||||||
wikicloth (= 0.8.1)
|
wikicloth (= 0.8.1)
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
|
|
|
@ -187,6 +187,9 @@ import './visibility_select';
|
||||||
import './wikis';
|
import './wikis';
|
||||||
import './zen_mode';
|
import './zen_mode';
|
||||||
|
|
||||||
|
// eslint-disable-next-line global-require
|
||||||
|
if (process.env.NODE_ENV !== 'production') require('./test_utils/');
|
||||||
|
|
||||||
document.addEventListener('beforeunload', function () {
|
document.addEventListener('beforeunload', function () {
|
||||||
// Unbind scroll events
|
// Unbind scroll events
|
||||||
$(document).off('scroll');
|
$(document).off('scroll');
|
||||||
|
|
4
app/assets/javascripts/test_utils/index.js
Normal file
4
app/assets/javascripts/test_utils/index.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import simulateDrag from './simulate_drag';
|
||||||
|
|
||||||
|
// Export to global space for rspec to use
|
||||||
|
window.simulateDrag = simulateDrag;
|
|
@ -1,58 +1,51 @@
|
||||||
/* eslint-disable wrap-iife, func-names, strict, no-var, vars-on-top, no-param-reassign, object-shorthand, no-shadow, comma-dangle, prefer-template, consistent-return, no-mixed-operators, no-unused-vars, no-unused-expressions, prefer-arrow-callback, max-len */
|
function simulateEvent(el, type, options = {}) {
|
||||||
(function () {
|
let event;
|
||||||
'use strict';
|
if (!el) return null;
|
||||||
|
|
||||||
function simulateEvent(el, type, options) {
|
|
||||||
var event;
|
|
||||||
if (!el) return;
|
|
||||||
var ownerDocument = el.ownerDocument;
|
|
||||||
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
if (/^mouse/.test(type)) {
|
if (/^mouse/.test(type)) {
|
||||||
event = ownerDocument.createEvent('MouseEvents');
|
event = el.ownerDocument.createEvent('MouseEvents');
|
||||||
event.initMouseEvent(type, true, true, ownerDocument.defaultView,
|
event.initMouseEvent(type, true, true, el.ownerDocument.defaultView,
|
||||||
options.button, options.screenX, options.screenY, options.clientX, options.clientY,
|
options.button, options.screenX, options.screenY, options.clientX, options.clientY,
|
||||||
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, el);
|
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, el);
|
||||||
} else {
|
} else {
|
||||||
event = ownerDocument.createEvent('CustomEvent');
|
event = el.ownerDocument.createEvent('CustomEvent');
|
||||||
|
|
||||||
event.initCustomEvent(type, true, true, ownerDocument.defaultView,
|
event.initCustomEvent(type, true, true, el.ownerDocument.defaultView,
|
||||||
options.button, options.screenX, options.screenY, options.clientX, options.clientY,
|
options.button, options.screenX, options.screenY, options.clientX, options.clientY,
|
||||||
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, el);
|
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, el);
|
||||||
|
|
||||||
event.dataTransfer = {
|
event.dataTransfer = {
|
||||||
data: {},
|
data: {},
|
||||||
|
|
||||||
setData: function (type, val) {
|
setData(key, val) {
|
||||||
this.data[type] = val;
|
this.data[key] = val;
|
||||||
},
|
},
|
||||||
|
|
||||||
getData: function (type) {
|
getData(key) {
|
||||||
return this.data[type];
|
return this.data[key];
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.dispatchEvent) {
|
if (el.dispatchEvent) {
|
||||||
el.dispatchEvent(event);
|
el.dispatchEvent(event);
|
||||||
} else if (el.fireEvent) {
|
} else if (el.fireEvent) {
|
||||||
el.fireEvent('on' + type, event);
|
el.fireEvent(`on${type}`, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isLast(target) {
|
function isLast(target) {
|
||||||
var el = typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el;
|
const el = typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el;
|
||||||
var children = el.children;
|
const children = el.children;
|
||||||
|
|
||||||
return children.length - 1 === target.index;
|
return children.length - 1 === target.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTarget(target) {
|
function getTarget(target) {
|
||||||
var el = typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el;
|
const el = typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el;
|
||||||
var children = el.children;
|
const children = el.children;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
children[target.index] ||
|
children[target.index] ||
|
||||||
|
@ -63,46 +56,52 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRect(el) {
|
function getRect(el) {
|
||||||
var rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
var width = rect.right - rect.left;
|
const width = rect.right - rect.left;
|
||||||
var height = rect.bottom - rect.top + 10;
|
const height = (rect.bottom - rect.top) + 10;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
x: rect.left,
|
x: rect.left,
|
||||||
y: rect.top,
|
y: rect.top,
|
||||||
cx: rect.left + width / 2,
|
cx: rect.left + (width / 2),
|
||||||
cy: rect.top + height / 2,
|
cy: rect.top + (height / 2),
|
||||||
w: width,
|
w: width,
|
||||||
h: height,
|
h: height,
|
||||||
hw: width / 2,
|
hw: width / 2,
|
||||||
wh: height / 2
|
wh: height / 2,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function simulateDrag(options, callback) {
|
export default function simulateDrag(options) {
|
||||||
options.to.el = options.to.el || options.from.el;
|
const { to, from } = options;
|
||||||
|
to.el = to.el || from.el;
|
||||||
|
|
||||||
var fromEl = getTarget(options.from);
|
const fromEl = getTarget(from);
|
||||||
var toEl = getTarget(options.to);
|
const toEl = getTarget(to);
|
||||||
var firstEl = getTarget({
|
const firstEl = getTarget({
|
||||||
el: options.to.el,
|
el: to.el,
|
||||||
index: 'first'
|
index: 'first',
|
||||||
});
|
});
|
||||||
var lastEl = getTarget({
|
const lastEl = getTarget({
|
||||||
el: options.to.el,
|
el: options.to.el,
|
||||||
index: 'last'
|
index: 'last',
|
||||||
});
|
});
|
||||||
var scrollable = options.scrollable;
|
|
||||||
|
|
||||||
var fromRect = getRect(fromEl);
|
const fromRect = getRect(fromEl);
|
||||||
var toRect = getRect(toEl);
|
const toRect = getRect(toEl);
|
||||||
var firstRect = getRect(firstEl);
|
const firstRect = getRect(firstEl);
|
||||||
var lastRect = getRect(lastEl);
|
const lastRect = getRect(lastEl);
|
||||||
|
|
||||||
var startTime = new Date().getTime();
|
const startTime = new Date().getTime();
|
||||||
var duration = options.duration || 1000;
|
const duration = options.duration || 1000;
|
||||||
simulateEvent(fromEl, 'mousedown', { button: 0 });
|
|
||||||
options.ontap && options.ontap();
|
simulateEvent(fromEl, 'mousedown', {
|
||||||
|
button: 0,
|
||||||
|
clientX: fromRect.cx,
|
||||||
|
clientY: fromRect.cy,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.ontap) options.ontap();
|
||||||
window.SIMULATE_DRAG_ACTIVE = 1;
|
window.SIMULATE_DRAG_ACTIVE = 1;
|
||||||
|
|
||||||
if (options.to.index === 0) {
|
if (options.to.index === 0) {
|
||||||
|
@ -111,19 +110,19 @@
|
||||||
toRect.cy = lastRect.y + lastRect.h + 50;
|
toRect.cy = lastRect.y + lastRect.h + 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
var dragInterval = setInterval(function loop() {
|
const dragInterval = setInterval(() => {
|
||||||
var progress = (new Date().getTime() - startTime) / duration;
|
const progress = (new Date().getTime() - startTime) / duration;
|
||||||
var x = (fromRect.cx + (toRect.cx - fromRect.cx) * progress) - scrollable.scrollLeft;
|
const x = (fromRect.cx + ((toRect.cx - fromRect.cx) * progress));
|
||||||
var y = (fromRect.cy + (toRect.cy - fromRect.cy) * progress) - scrollable.scrollTop;
|
const y = (fromRect.cy + ((toRect.cy - fromRect.cy) * progress));
|
||||||
var overEl = fromEl.ownerDocument.elementFromPoint(x, y);
|
const overEl = fromEl.ownerDocument.elementFromPoint(x, y);
|
||||||
|
|
||||||
simulateEvent(overEl, 'mousemove', {
|
simulateEvent(overEl, 'mousemove', {
|
||||||
clientX: x,
|
clientX: x,
|
||||||
clientY: y
|
clientY: y,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (progress >= 1) {
|
if (progress >= 1) {
|
||||||
options.ondragend && options.ondragend();
|
if (options.ondragend) options.ondragend();
|
||||||
simulateEvent(toEl, 'mouseup');
|
simulateEvent(toEl, 'mouseup');
|
||||||
clearInterval(dragInterval);
|
clearInterval(dragInterval);
|
||||||
window.SIMULATE_DRAG_ACTIVE = 0;
|
window.SIMULATE_DRAG_ACTIVE = 0;
|
||||||
|
@ -133,11 +132,6 @@
|
||||||
return {
|
return {
|
||||||
target: fromEl,
|
target: fromEl,
|
||||||
fromList: fromEl.parentNode,
|
fromList: fromEl.parentNode,
|
||||||
toList: toEl.parentNode
|
toList: toEl.parentNode,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export
|
|
||||||
window.simulateEvent = simulateEvent;
|
|
||||||
window.simulateDrag = simulateDrag;
|
|
||||||
})();
|
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
= render "header_title"
|
= render "header_title"
|
||||||
|
|
||||||
- content_for :page_specific_javascripts do
|
|
||||||
= page_specific_javascript_bundle_tag('simulate_drag') if Rails.env.test?
|
|
||||||
|
|
||||||
= render 'shared/milestones/top', milestone: @milestone, group: @group
|
= render 'shared/milestones/top', milestone: @milestone, group: @group
|
||||||
= render 'shared/milestones/tabs', milestone: @milestone, show_project_name: true
|
= render 'shared/milestones/tabs', milestone: @milestone, show_project_name: true
|
||||||
= render 'shared/milestones/sidebar', milestone: @milestone, affix_offset: 102
|
= render 'shared/milestones/sidebar', milestone: @milestone, affix_offset: 102
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
= page_specific_javascript_bundle_tag('common_vue')
|
= page_specific_javascript_bundle_tag('common_vue')
|
||||||
= page_specific_javascript_bundle_tag('filtered_search')
|
= page_specific_javascript_bundle_tag('filtered_search')
|
||||||
= page_specific_javascript_bundle_tag('boards')
|
= page_specific_javascript_bundle_tag('boards')
|
||||||
= page_specific_javascript_bundle_tag('simulate_drag') if Rails.env.test?
|
|
||||||
|
|
||||||
%script#js-board-template{ type: "text/x-template" }= render "projects/boards/components/board"
|
%script#js-board-template{ type: "text/x-template" }= render "projects/boards/components/board"
|
||||||
%script#js-board-list-template{ type: "text/x-template" }= render "projects/boards/components/board_list"
|
%script#js-board-list-template{ type: "text/x-template" }= render "projects/boards/components/board_list"
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
- hide_class = ''
|
- hide_class = ''
|
||||||
= render "projects/issues/head"
|
= render "projects/issues/head"
|
||||||
|
|
||||||
- content_for :page_specific_javascripts do
|
|
||||||
= page_specific_javascript_bundle_tag('simulate_drag') if Rails.env.test?
|
|
||||||
|
|
||||||
- if @labels.exists? || @prioritized_labels.exists?
|
- if @labels.exists? || @prioritized_labels.exists?
|
||||||
%div{ class: container_class }
|
%div{ class: container_class }
|
||||||
.top-area.adjust
|
.top-area.adjust
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
- page_description @milestone.description
|
- page_description @milestone.description
|
||||||
= render "projects/issues/head"
|
= render "projects/issues/head"
|
||||||
|
|
||||||
- content_for :page_specific_javascripts do
|
|
||||||
= page_specific_javascript_bundle_tag('simulate_drag') if Rails.env.test?
|
|
||||||
|
|
||||||
%div{ class: container_class }
|
%div{ class: container_class }
|
||||||
.detail-page-header.milestone-page-header
|
.detail-page-header.milestone-page-header
|
||||||
.status-box{ class: status_box_class(@milestone) }
|
.status-box{ class: status_box_class(@milestone) }
|
||||||
|
|
|
@ -23,7 +23,6 @@ var config = {
|
||||||
main: './main.js',
|
main: './main.js',
|
||||||
blob: './blob_edit/blob_bundle.js',
|
blob: './blob_edit/blob_bundle.js',
|
||||||
boards: './boards/boards_bundle.js',
|
boards: './boards/boards_bundle.js',
|
||||||
simulate_drag: './test_utils/simulate_drag.js',
|
|
||||||
cycle_analytics: './cycle_analytics/cycle_analytics_bundle.js',
|
cycle_analytics: './cycle_analytics/cycle_analytics_bundle.js',
|
||||||
commit_pipelines: './commit/pipelines/pipelines_bundle.js',
|
commit_pipelines: './commit/pipelines/pipelines_bundle.js',
|
||||||
diff_notes: './diff_notes/diff_notes_bundle.js',
|
diff_notes: './diff_notes/diff_notes_bundle.js',
|
||||||
|
|
|
@ -76,6 +76,7 @@ describe 'Milestone draggable', feature: true, js: true do
|
||||||
create(:issue, params.merge(title: 'Foo', project: project, milestone: milestone))
|
create(:issue, params.merge(title: 'Foo', project: project, milestone: milestone))
|
||||||
|
|
||||||
visit namespace_project_milestone_path(project.namespace, project, milestone)
|
visit namespace_project_milestone_path(project.namespace, project, milestone)
|
||||||
|
scroll_into_view('.milestone-content')
|
||||||
drag_to(selector: '.issues-sortable-list', list_to_index: 1)
|
drag_to(selector: '.issues-sortable-list', list_to_index: 1)
|
||||||
|
|
||||||
wait_for_ajax
|
wait_for_ajax
|
||||||
|
@ -86,8 +87,13 @@ describe 'Milestone draggable', feature: true, js: true do
|
||||||
|
|
||||||
visit namespace_project_milestone_path(project.namespace, project, milestone)
|
visit namespace_project_milestone_path(project.namespace, project, milestone)
|
||||||
page.find("a[href='#tab-merge-requests']").click
|
page.find("a[href='#tab-merge-requests']").click
|
||||||
|
scroll_into_view('.milestone-content')
|
||||||
drag_to(selector: '.merge_requests-sortable-list', list_to_index: 1)
|
drag_to(selector: '.merge_requests-sortable-list', list_to_index: 1)
|
||||||
|
|
||||||
wait_for_ajax
|
wait_for_ajax
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def scroll_into_view(selector)
|
||||||
|
page.evaluate_script("document.querySelector('#{selector}').scrollIntoView();")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,11 +3,11 @@ module DragTo
|
||||||
evaluate_script("simulateDrag({scrollable: $('#{scrollable}').get(0), from: {el: $('#{selector}').eq(#{list_from_index}).get(0), index: #{from_index}}, to: {el: $('#{selector}').eq(#{list_to_index}).get(0), index: #{to_index}}});")
|
evaluate_script("simulateDrag({scrollable: $('#{scrollable}').get(0), from: {el: $('#{selector}').eq(#{list_from_index}).get(0), index: #{from_index}}, to: {el: $('#{selector}').eq(#{list_to_index}).get(0), index: #{to_index}}});")
|
||||||
|
|
||||||
Timeout.timeout(Capybara.default_max_wait_time) do
|
Timeout.timeout(Capybara.default_max_wait_time) do
|
||||||
loop until drag_active?
|
loop while drag_active?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def drag_active?
|
def drag_active?
|
||||||
page.evaluate_script('window.SIMULATE_DRAG_ACTIVE').zero?
|
page.evaluate_script('window.SIMULATE_DRAG_ACTIVE').nonzero?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue