diff options
-rw-r--r-- | .gitlab-ci.yml | 3 | ||||
-rw-r--r-- | Gemfile | 2 | ||||
-rw-r--r-- | Gemfile.lock | 6 | ||||
-rw-r--r-- | app/assets/javascripts/main.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/test_utils/index.js | 4 | ||||
-rw-r--r-- | app/assets/javascripts/test_utils/simulate_drag.js | 262 | ||||
-rw-r--r-- | app/views/groups/milestones/show.html.haml | 4 | ||||
-rw-r--r-- | app/views/projects/boards/_show.html.haml | 1 | ||||
-rw-r--r-- | app/views/projects/labels/index.html.haml | 3 | ||||
-rw-r--r-- | app/views/projects/milestones/show.html.haml | 3 | ||||
-rw-r--r-- | config/webpack.config.js | 1 | ||||
-rw-r--r-- | spec/features/milestones/milestones_spec.rb | 6 | ||||
-rw-r--r-- | spec/support/drag_to_helper.rb | 4 |
13 files changed, 148 insertions, 154 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f2fb6d3101c..66f8b6e6f9a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,6 +8,7 @@ cache: variables: MYSQL_ALLOW_EMPTY_PASSWORD: "1" RAILS_ENV: "test" + NODE_ENV: "test" SIMPLECOV: "true" SETUP_DB: "true" USE_BUNDLE_INSTALL: "true" @@ -129,9 +130,7 @@ setup-test-env: stage: prepare script: - node --version - - yarn --version - yarn install --pure-lockfile - - yarn check # ensure that yarn.lock matches package.json - bundle exec rake gitlab:assets:compile - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init' artifacts: @@ -223,7 +223,7 @@ gem 'oj', '~> 2.17.4' gem 'chronic', '~> 0.10.2' 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 'sass-rails', '~> 5.0.6' diff --git a/Gemfile.lock b/Gemfile.lock index 304fc9f2bb3..50ca9af7a7a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -823,8 +823,8 @@ GEM addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff - webpack-rails (0.9.9) - rails (>= 3.2.0) + webpack-rails (0.9.10) + railties (>= 3.2.0) websocket-driver (0.6.3) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) @@ -1026,7 +1026,7 @@ DEPENDENCIES virtus (~> 1.0.1) vmstat (~> 2.3.0) webmock (~> 1.24.0) - webpack-rails (~> 0.9.9) + webpack-rails (~> 0.9.10) wikicloth (= 0.8.1) BUNDLED WITH diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 665a59f3183..5b50bc62876 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -187,6 +187,9 @@ import './visibility_select'; import './wikis'; import './zen_mode'; +// eslint-disable-next-line global-require +if (process.env.NODE_ENV !== 'production') require('./test_utils/'); + document.addEventListener('beforeunload', function () { // Unbind scroll events $(document).off('scroll'); diff --git a/app/assets/javascripts/test_utils/index.js b/app/assets/javascripts/test_utils/index.js new file mode 100644 index 00000000000..ef401abce2d --- /dev/null +++ b/app/assets/javascripts/test_utils/index.js @@ -0,0 +1,4 @@ +import simulateDrag from './simulate_drag'; + +// Export to global space for rspec to use +window.simulateDrag = simulateDrag; diff --git a/app/assets/javascripts/test_utils/simulate_drag.js b/app/assets/javascripts/test_utils/simulate_drag.js index d48f2404fa5..e39213cb098 100644 --- a/app/assets/javascripts/test_utils/simulate_drag.js +++ b/app/assets/javascripts/test_utils/simulate_drag.js @@ -1,143 +1,137 @@ -/* 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 () { - 'use strict'; - - function simulateEvent(el, type, options) { - var event; - if (!el) return; - var ownerDocument = el.ownerDocument; - - options = options || {}; - - if (/^mouse/.test(type)) { - event = ownerDocument.createEvent('MouseEvents'); - event.initMouseEvent(type, true, true, ownerDocument.defaultView, - options.button, options.screenX, options.screenY, options.clientX, options.clientY, - options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, el); - } else { - event = ownerDocument.createEvent('CustomEvent'); - - event.initCustomEvent(type, true, true, ownerDocument.defaultView, - options.button, options.screenX, options.screenY, options.clientX, options.clientY, - options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, el); - - event.dataTransfer = { - data: {}, - - setData: function (type, val) { - this.data[type] = val; - }, - - getData: function (type) { - return this.data[type]; - } - }; - } - - if (el.dispatchEvent) { - el.dispatchEvent(event); - } else if (el.fireEvent) { - el.fireEvent('on' + type, event); - } - - return event; - } - - function isLast(target) { - var el = typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el; - var children = el.children; - - return children.length - 1 === target.index; +function simulateEvent(el, type, options = {}) { + let event; + if (!el) return null; + + if (/^mouse/.test(type)) { + event = el.ownerDocument.createEvent('MouseEvents'); + event.initMouseEvent(type, true, true, el.ownerDocument.defaultView, + options.button, options.screenX, options.screenY, options.clientX, options.clientY, + options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, el); + } else { + event = el.ownerDocument.createEvent('CustomEvent'); + + event.initCustomEvent(type, true, true, el.ownerDocument.defaultView, + options.button, options.screenX, options.screenY, options.clientX, options.clientY, + options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, el); + + event.dataTransfer = { + data: {}, + + setData(key, val) { + this.data[key] = val; + }, + + getData(key) { + return this.data[key]; + }, + }; } - function getTarget(target) { - var el = typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el; - var children = el.children; - - return ( - children[target.index] || - children[target.index === 'first' ? 0 : -1] || - children[target.index === 'last' ? children.length - 1 : -1] || - el - ); + if (el.dispatchEvent) { + el.dispatchEvent(event); + } else if (el.fireEvent) { + el.fireEvent(`on${type}`, event); } - function getRect(el) { - var rect = el.getBoundingClientRect(); - var width = rect.right - rect.left; - var height = rect.bottom - rect.top + 10; - - return { - x: rect.left, - y: rect.top, - cx: rect.left + width / 2, - cy: rect.top + height / 2, - w: width, - h: height, - hw: width / 2, - wh: height / 2 - }; + return event; +} + +function isLast(target) { + const el = typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el; + const children = el.children; + + return children.length - 1 === target.index; +} + +function getTarget(target) { + const el = typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el; + const children = el.children; + + return ( + children[target.index] || + children[target.index === 'first' ? 0 : -1] || + children[target.index === 'last' ? children.length - 1 : -1] || + el + ); +} + +function getRect(el) { + const rect = el.getBoundingClientRect(); + const width = rect.right - rect.left; + const height = (rect.bottom - rect.top) + 10; + + return { + x: rect.left, + y: rect.top, + cx: rect.left + (width / 2), + cy: rect.top + (height / 2), + w: width, + h: height, + hw: width / 2, + wh: height / 2, + }; +} + +export default function simulateDrag(options) { + const { to, from } = options; + to.el = to.el || from.el; + + const fromEl = getTarget(from); + const toEl = getTarget(to); + const firstEl = getTarget({ + el: to.el, + index: 'first', + }); + const lastEl = getTarget({ + el: options.to.el, + index: 'last', + }); + + const fromRect = getRect(fromEl); + const toRect = getRect(toEl); + const firstRect = getRect(firstEl); + const lastRect = getRect(lastEl); + + const startTime = new Date().getTime(); + const duration = options.duration || 1000; + + simulateEvent(fromEl, 'mousedown', { + button: 0, + clientX: fromRect.cx, + clientY: fromRect.cy, + }); + + if (options.ontap) options.ontap(); + window.SIMULATE_DRAG_ACTIVE = 1; + + if (options.to.index === 0) { + toRect.cy = firstRect.y; + } else if (isLast(options.to)) { + toRect.cy = lastRect.y + lastRect.h + 50; } - function simulateDrag(options, callback) { - options.to.el = options.to.el || options.from.el; + const dragInterval = setInterval(() => { + const progress = (new Date().getTime() - startTime) / duration; + const x = (fromRect.cx + ((toRect.cx - fromRect.cx) * progress)); + const y = (fromRect.cy + ((toRect.cy - fromRect.cy) * progress)); + const overEl = fromEl.ownerDocument.elementFromPoint(x, y); - var fromEl = getTarget(options.from); - var toEl = getTarget(options.to); - var firstEl = getTarget({ - el: options.to.el, - index: 'first' + simulateEvent(overEl, 'mousemove', { + clientX: x, + clientY: y, }); - var lastEl = getTarget({ - el: options.to.el, - index: 'last' - }); - var scrollable = options.scrollable; - - var fromRect = getRect(fromEl); - var toRect = getRect(toEl); - var firstRect = getRect(firstEl); - var lastRect = getRect(lastEl); - - var startTime = new Date().getTime(); - var duration = options.duration || 1000; - simulateEvent(fromEl, 'mousedown', { button: 0 }); - options.ontap && options.ontap(); - window.SIMULATE_DRAG_ACTIVE = 1; - - if (options.to.index === 0) { - toRect.cy = firstRect.y; - } else if (isLast(options.to)) { - toRect.cy = lastRect.y + lastRect.h + 50; - } - var dragInterval = setInterval(function loop() { - var progress = (new Date().getTime() - startTime) / duration; - var x = (fromRect.cx + (toRect.cx - fromRect.cx) * progress) - scrollable.scrollLeft; - var y = (fromRect.cy + (toRect.cy - fromRect.cy) * progress) - scrollable.scrollTop; - var overEl = fromEl.ownerDocument.elementFromPoint(x, y); - - simulateEvent(overEl, 'mousemove', { - clientX: x, - clientY: y - }); - - if (progress >= 1) { - options.ondragend && options.ondragend(); - simulateEvent(toEl, 'mouseup'); - clearInterval(dragInterval); - window.SIMULATE_DRAG_ACTIVE = 0; - } - }, 100); - - return { - target: fromEl, - fromList: fromEl.parentNode, - toList: toEl.parentNode - }; - } - - // Export - window.simulateEvent = simulateEvent; - window.simulateDrag = simulateDrag; -})(); + if (progress >= 1) { + if (options.ondragend) options.ondragend(); + simulateEvent(toEl, 'mouseup'); + clearInterval(dragInterval); + window.SIMULATE_DRAG_ACTIVE = 0; + } + }, 100); + + return { + target: fromEl, + fromList: fromEl.parentNode, + toList: toEl.parentNode, + }; +} diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml index 8e83b2002b2..33e68bc766e 100644 --- a/app/views/groups/milestones/show.html.haml +++ b/app/views/groups/milestones/show.html.haml @@ -1,8 +1,4 @@ = 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/tabs', milestone: @milestone, show_project_name: true = render 'shared/milestones/sidebar', milestone: @milestone, affix_offset: 102 diff --git a/app/views/projects/boards/_show.html.haml b/app/views/projects/boards/_show.html.haml index added3f669b..d93eac63bd3 100644 --- a/app/views/projects/boards/_show.html.haml +++ b/app/views/projects/boards/_show.html.haml @@ -6,7 +6,6 @@ = page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('filtered_search') = 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-list-template{ type: "text/x-template" }= render "projects/boards/components/board_list" diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml index 8d4a91cb64c..29f861c09c6 100644 --- a/app/views/projects/labels/index.html.haml +++ b/app/views/projects/labels/index.html.haml @@ -3,9 +3,6 @@ - hide_class = '' = 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? %div{ class: container_class } .top-area.adjust diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index f612b5c7d6b..5249d752585 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -3,9 +3,6 @@ - page_description @milestone.description = 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 } .detail-page-header.milestone-page-header .status-box{ class: status_box_class(@milestone) } diff --git a/config/webpack.config.js b/config/webpack.config.js index 70d98b022c1..728c2a64053 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -23,7 +23,6 @@ var config = { main: './main.js', blob: './blob_edit/blob_bundle.js', boards: './boards/boards_bundle.js', - simulate_drag: './test_utils/simulate_drag.js', cycle_analytics: './cycle_analytics/cycle_analytics_bundle.js', commit_pipelines: './commit/pipelines/pipelines_bundle.js', diff_notes: './diff_notes/diff_notes_bundle.js', diff --git a/spec/features/milestones/milestones_spec.rb b/spec/features/milestones/milestones_spec.rb index 8de9942c54e..2fa3e72ab08 100644 --- a/spec/features/milestones/milestones_spec.rb +++ b/spec/features/milestones/milestones_spec.rb @@ -76,6 +76,7 @@ describe 'Milestone draggable', feature: true, js: true do create(:issue, params.merge(title: 'Foo', project: project, milestone: 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) wait_for_ajax @@ -86,8 +87,13 @@ describe 'Milestone draggable', feature: true, js: true do visit namespace_project_milestone_path(project.namespace, project, milestone) page.find("a[href='#tab-merge-requests']").click + scroll_into_view('.milestone-content') drag_to(selector: '.merge_requests-sortable-list', list_to_index: 1) wait_for_ajax end + + def scroll_into_view(selector) + page.evaluate_script("document.querySelector('#{selector}').scrollIntoView();") + end end diff --git a/spec/support/drag_to_helper.rb b/spec/support/drag_to_helper.rb index 0c0659d3ecd..ae149631ed9 100644 --- a/spec/support/drag_to_helper.rb +++ b/spec/support/drag_to_helper.rb @@ -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}}});") Timeout.timeout(Capybara.default_max_wait_time) do - loop until drag_active? + loop while drag_active? end end def drag_active? - page.evaluate_script('window.SIMULATE_DRAG_ACTIVE').zero? + page.evaluate_script('window.SIMULATE_DRAG_ACTIVE').nonzero? end end |