## Mercury general steps #------------------------------------------------------------------------------ Given /^(?:|I )adjust the configuration to have: \{([^\}]*)\}$/ do |javascript| Rails.application.config.mercury_config = JSON.parse("{#{javascript}}") end # scoping step for the mercury content frame When /^(.*) in the content frame$/ do |s| page.driver.within_frame('mercury_iframe') do step(s) end end # silence mercury's onbeforeunload confirmation Given /^the editor won't prompt when leaving the page$/ do page.driver.execute_script('Mercury.silent = true;') end ## Toolbar specific steps #------------------------------------------------------------------------------ # for the select dropdowns When /^(?:|I )select (.*?) from the dropdown$/ do |locator| selector = selector_for(locator) find(selector, :message => "Unable to locate the element '#{selector}' to click on").click end ## Panel specific steps #------------------------------------------------------------------------------ When /^(?:I )(?:open|close|toggle) the (.*?) panel$/ do |panel_locator| step(%Q{I click on the "#{panel_locator}" button}) end ## Modal specific steps #------------------------------------------------------------------------------ When /^(?:I )close the modal(?: window)?$/ do step(%Q{I click on the modal close button}) end ## Region specific steps #------------------------------------------------------------------------------ # setting content Given /^the content of (.*?) (?:is|are|has|includes) (.*?)$/ do |region_locator, contents| step(%Q{I set the contents of #{region_locator} to #{contents}}) end When /^(?:|I )(?:change|set) the contents? of (.*?) to (.*?)$/ do |region_locator, contents| region_id = region_selector_for(region_locator).gsub('#', '') content = contents[0] == '"' ? contents : "\"#{contents_for(contents)}\"" page.driver.within_frame('mercury_iframe') do find("##{region_id}", :message => "Unable to locate a region matching '##{region_id}'") page.driver.execute_script <<-JAVASCRIPT var element = top.jQuery(document).find('##{region_id}'); if (element.data('type') == 'markdown') { element.find('textarea').val(#{content}); } else { var region = top.mercuryInstance.getRegionByName('#{region_id}'); region.content(#{content}); } JAVASCRIPT end end When /^(?:|I )focus on (.*?)$/ do |region_locator| step(%Q{I can simulate complex javascript events}) region_selector = region_selector_for(region_locator) page.driver.within_frame('mercury_iframe') do page.driver.execute_script <<-JAVASCRIPT top.jQuery(document).find('#{region_selector}').simulate('mouseup') JAVASCRIPT end end # setting/making selections When /^(?:|I )(?:make|have) a selection$/ do step(%Q{I have a selection for "span"}) end When /^(?:|I )(?:make|have) a selection (?:in (.*?) )?for "([^"]*)"$/ do |region_locator, selector| step(%Q{I can simulate complex javascript events}) # assume the first full region if one wasn't provided' region_selector = region_selector_for(region_locator) page.driver.within_frame('mercury_iframe') do find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'") find("#{region_selector} #{selector}", :message => "Unable to locate a match for '#{selector}' inside '#{region_locator}'") page.driver.execute_script <<-JAVASCRIPT var element = top.jQuery(document).find('#{region_selector}'); if (element.data('type') == 'markdown') { alert('unimplemented'); throw('unimplemented'); } else { var selectedElement = element.find('#{selector}'); var selection = new top.Mercury.Regions.Full.Selection(window.getSelection(), document); selection.selectNode(selectedElement.get(0)); selectedElement.simulate('mouseup'); } JAVASCRIPT end end # other events When /^(?:|I )double click on (.*?) in (.*?)$/ do |locator, region_locator| step(%Q{I can simulate complex javascript events}) selector = selector_for(locator) # assume the first full region if one wasn't provided' region_selector = region_selector_for(region_locator) page.driver.within_frame('mercury_iframe') do find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'") find("#{region_selector} #{selector}", :message => "Unable to locate a match for '#{selector}' inside '#{region_selector}'") page.driver.execute_script <<-JAVASCRIPT top.jQuery(document).find('#{region_selector} #{selector}').simulate('dblclick'); JAVASCRIPT end end # getting contents Then /^the contents? of (.*?) should be "([^"]*)"$/ do |region_locator, content| region_selector = region_selector_for(region_locator) page.driver.within_frame('mercury_iframe') do find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'") results = page.driver.execute_script <<-JAVASCRIPT var element = top.jQuery(document).find('#{region_selector}'); if (element.data('type') == 'markdown') { return element.find('textarea').val(); } else { return element.html(); } JAVASCRIPT assert_equal content, results.gsub('"', "'").gsub("\n", '') end end ## Saving specific steps #------------------------------------------------------------------------------ # caching for the last save -- a request will still be made Given /^save results will be cached$/ do page.driver.execute_script <<-JAVASCRIPT Mercury.PageEditor.prototype.save = function() { window.cachedResults = this.serialize(); Mercury.changes = false; } JAVASCRIPT end # check for the last save cached results Then /^the save should have (.*?) for (.*?)$/ do |contents, region_locator| region_id = region_selector_for(region_locator).gsub('#', '') content = contents[0] == '"' ? contents : "\"#{contents_for(contents)}\"" results = page.driver.execute_script <<-JAVASCRIPT return (window.cachedResults['#{region_id}']) ? window.cachedResults['#{region_id}']['value'] : null; JAVASCRIPT assert_equal content, "\"#{results}\"" end ## Table editing specific steps #------------------------------------------------------------------------------ # in the modal window When /^(?:|I )(?:add|insert) a (row|column) (before|after)(?: it)?$/ do |row_or_column, before_or_after| name = "add_#{row_or_column}_#{before_or_after}".camelcase(:lower) step(%Q{I click on ".mercury-modal-content button[data-action='#{name}']"}) end When /^(?:|I )delete the(?: current)? (row|column)$/ do |row_or_column| name = "remove_#{row_or_column}".camelcase(:lower) step(%Q{I click on ".mercury-modal-content button[data-action='#{name}']"}) end When /^(?:|I )(increase|decrease) the (rowspan|colspan)$/ do |increase_or_decrease, rowspan_or_colspan| name = "#{increase_or_decrease}_#{rowspan_or_colspan}".camelcase(:lower) step(%Q{I click on ".mercury-modal-content button[data-action=#{name}]"}) end Then /^the selected cell should be (.*?)$/ do |locator| selector = selector_for(locator).gsub('td:', 'td.selected:') find("#{selector}", :message => "Unable to locate the selected cell for '#{selector}'") end # in general Then /^the(?: table)? (row|column) count should be (\d+)$/ do |row_or_column, expected_count| method = "get_#{row_or_column}_count".camelcase(:lower) actual_count = page.driver.execute_script("return Mercury.tableEditor.#{method}()") assert_equal expected_count.to_i, actual_count.to_i end ## Snippet specific steps #------------------------------------------------------------------------------ # setting snippet options Given /^the options for the (.*?) snippet "([^"]*)" are (.*?)$/ do |snippet_name, snippet_id, options| @snippet_id = snippet_id options_json = parse_snippet_options_from(options) page.driver.execute_script <<-JAVASCRIPT Mercury.Snippet.load({#{snippet_id}: {name: '#{snippet_name}', options: #{options_json}}}); JAVASCRIPT end # dragging/dropping When /^(?:|I )(?:drag|drop) (.*?) (?:into|on) (.*?)$/ do |snippet_locator, region_locator| snippet_name = snippet_name_for(snippet_locator) region_id = region_selector_for(region_locator).gsub('#', '') page.driver.within_frame('mercury_iframe') do find("##{region_id}", :message => "Unable to locate a region matching '##{region_id}'") data = " data-snippet=\"#{snippet_name}\"" data << ' data-options="false"' if snippet_name == 'no_options' page.driver.execute_script <<-JAVASCRIPT var element = top.jQuery(document).find('##{region_id}'); if (element.data('type') == 'markdown') { alert('unimplemented'); throw('unimplemented'); } else { var region = top.mercuryInstance.getRegionByName('#{region_id}'); region.selection().range.collapse(true); document.execCommand('insertHTML', false, ''); element.trigger('possible:drop'); } JAVASCRIPT end end When /^(?:|I )hover over (.*?)(?: in (.*?))?$/ do |locator, region_locator| step(%Q{I can simulate complex javascript events}) selector = selector_for(locator) region_selector = region_selector_for(region_locator) page.driver.within_frame('mercury_iframe') do find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'") page.driver.execute_script <<-JAVASCRIPT var element = top.jQuery(document).find('#{region_selector}'); if (element.data('type') == 'markdown') { alert('unimplemented'); throw('unimplemented'); } else { element.find('#{selector}').simulate('mousemove'); } JAVASCRIPT end end When /^(?:|I )edit the snippet$/ do step(%{I hover over the snippet}) step(%{I click on the edit snippet settings toolbar button}) end ## Javascript event simulation steps #------------------------------------------------------------------------------ Given /^(?:|I )can simulate complex javascript events$/ do page.driver.execute_script(JQUERY_EVENT_SIMULATION_JAVASCRIPT) end #------------------------------------------------------------------------------ JQUERY_EVENT_SIMULATION_JAVASCRIPT = <<-JAVASCRIPT /* * jquery.simulate - simulate browser mouse and keyboard events * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * */ ;(function($) { $.fn.extend({ simulate: function(type, options) { return this.each(function() { var opt = $.extend({}, $.simulate.defaults, options || {}); new $.simulate(this, type, opt); }); } }); $.simulate = function(el, type, options) { this.target = el; this.options = options; if (/^drag$/.test(type)) { this[type].apply(this, [this.target, options]); } else { this.simulateEvent(el, type, options); } } $.extend($.simulate.prototype, { simulateEvent: function(el, type, options) { var evt = this.createEvent(type, options); this.dispatchEvent(el, type, evt, options); return evt; }, createEvent: function(type, options) { if (/^mouse(over|out|down|up|move)|(dbl)?click$/.test(type)) { return this.mouseEvent(type, options); } else if (/^key(up|down|press)$/.test(type)) { return this.keyboardEvent(type, options); } }, mouseEvent: function(type, options) { var evt; var e = $.extend({ bubbles: true, cancelable: (type != "mousemove"), view: window, detail: 0, screenX: 0, screenY: 0, clientX: 0, clientY: 0, ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, button: 0, relatedTarget: undefined }, options); var relatedTarget = $(e.relatedTarget)[0]; if ($.isFunction(document.createEvent)) { evt = document.createEvent("MouseEvents"); evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget || document.body.parentNode); } else if (document.createEventObject) { evt = document.createEventObject(); $.extend(evt, e); evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button; } return evt; }, keyboardEvent: function(type, options) { var evt; var e = $.extend({ bubbles: true, cancelable: true, view: window, ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, keyCode: 0, charCode: 0 }, options); if ($.isFunction(document.createEvent)) { try { evt = document.createEvent("KeyEvents"); evt.initKeyEvent(type, e.bubbles, e.cancelable, e.view, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.keyCode, e.charCode); } catch(err) { evt = document.createEvent("Events"); evt.initEvent(type, e.bubbles, e.cancelable); $.extend(evt, { view: e.view, ctrlKey: e.ctrlKey, altKey: e.altKey, shiftKey: e.shiftKey, metaKey: e.metaKey, keyCode: e.keyCode, charCode: e.charCode }); } } else if (document.createEventObject) { evt = document.createEventObject(); $.extend(evt, e); } if ($.browser.msie || $.browser.opera) { evt.keyCode = (e.charCode > 0) ? e.charCode : e.keyCode; evt.charCode = undefined; } return evt; }, dispatchEvent: function(el, type, evt) { if (el.dispatchEvent) { el.dispatchEvent(evt); } else if (el.fireEvent) { el.fireEvent('on' + type, evt); } return evt; }, drag: function(el) { var self = this, center = this.findCenter(this.target), options = this.options, x = Math.floor(center.x), y = Math.floor(center.y), dx = options.dx || 0, dy = options.dy || 0, target = this.target; var coord = { clientX: x, clientY: y }; this.simulateEvent(target, "mousedown", coord); coord = { clientX: x + 1, clientY: y + 1 }; this.simulateEvent(document, "mousemove", coord); coord = { clientX: x + dx, clientY: y + dy }; this.simulateEvent(document, "mousemove", coord); this.simulateEvent(document, "mousemove", coord); this.simulateEvent(target, "mouseup", coord); this.simulateEvent(target, "click", coord); }, findCenter: function(el) { var el = $(this.target), o = el.offset(), d = $(document); return { x: o.left + el.outerWidth() / 2 - d.scrollLeft(), y: o.top + el.outerHeight() / 2 - d.scrollTop() }; } }); $.extend($.simulate, { defaults: { speed: 'sync' }, VK_TAB: 9, VK_ENTER: 13, VK_ESC: 27, VK_PGUP: 33, VK_PGDN: 34, VK_END: 35, VK_HOME: 36, VK_LEFT: 37, VK_UP: 38, VK_RIGHT: 39, VK_DOWN: 40 }); })(jQuery); JAVASCRIPT