Created
April 29, 2016 14:13
-
-
Save wied03/a6b198a6d8820e8328037183e7b5c6f1 to your computer and use it in GitHub Desktop.
React tests with RSpec
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'components/base' | |
require 'react-opal' | |
require 'components/mixins/default' | |
class Components::Base::Option | |
include React::Component | |
include Components::Mixins::Default | |
def option_args | |
result = { value: params[:value] } | |
with_non_nil_attributes! result, :disabled | |
end | |
def render | |
option option_args do | |
params[:children] | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'spec_helper' | |
require 'components/base/option' | |
describe Components::Base::Option do | |
include_context :react_component_testing | |
describe '#render' do | |
context 'enabled' do | |
let(:react_arguments) { { value: '22', children: 'whatup' } } | |
it { is_expected.to render_markup '<option value="22">whatup</option>' } | |
end | |
context 'disabled' do | |
let(:react_arguments) { { value: '22', children: 'whatup', disabled: true } } | |
it { is_expected.to render_markup '<option value="22" disabled="">whatup</option>' } | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# :reek:BooleanParameter and :reek:ControlParameter and :reek:DataClump | |
module ReactDomHelpers | |
def render_element(react_element) | |
`React.addons.TestUtils.renderIntoDocument(#{react_element})` | |
end | |
def get_markup_without_id(rendered_element = subject) | |
dom_node = React.find_dom_node rendered_element | |
html_with_id = `#{dom_node}.outerHTML` | |
html_with_id.gsub /\sdata-reactid=".*?"/, '' | |
end | |
def get_dom_node(rendered_element) | |
React.find_dom_node rendered_element | |
end | |
def get_jq_node(rendered_element) | |
dom_node = get_dom_node rendered_element | |
dom_node ? Element.find(dom_node) : nil | |
end | |
# TODO: Improve this | |
# rubocop:disable Metrics/PerceivedComplexity | |
def find_element_jq_nodes(rendered_element, element_type, element_id = nil, element_name = nil, use_self = false) | |
jq_dom_node = get_jq_node rendered_element | |
return nil unless jq_dom_node | |
if use_self | |
matching = jq_dom_node.tag_name == element_type | |
matching &&= if element_id | |
jq_dom_node.id == element_id | |
else | |
jq_dom_node[:name] == element_name | |
end | |
return matching ? jq_dom_node : nil | |
end | |
search_clause = if element_id | |
"#{element_type}[id=#{element_id}]" | |
elsif element_name | |
"#{element_type}[name='#{element_name}']" | |
else | |
element_type | |
end | |
elements = jq_dom_node.find(search_clause) | |
elements.any? ? elements : nil | |
end | |
# rubocop:enable Metrics/PerceivedComplexity | |
def get_unresolved_promise(rendered_element) | |
# if we're operating on this from the before block, we may not have a resolved subject yet | |
if rendered_element.is_a? Promise | |
rendered_element.resolved? ? Promise.value(rendered_element.value) : rendered_element | |
else | |
Promise.value rendered_element | |
end | |
end | |
def simulate_click(jq_node, descriptor) | |
info_prefix = "Button #{descriptor} click process" | |
puts "#{info_prefix} Triggering change event with React" if output_debug_messages | |
native_node = jq_node.get[0] | |
`React.addons.TestUtils.Simulate.click(#{native_node})` | |
puts "#{info_prefix} Trigger complete" if output_debug_messages | |
end | |
def click_button(element_id: nil, | |
button_text: nil, | |
use_self: false) | |
promise = get_unresolved_promise rendered_element | |
# With Opal, named arguments won't be found inside the block, so re-declare them here | |
# rubocop:disable Style/ParallelAssignment | |
element_id, button_text, use_self = [element_id, button_text, use_self] | |
# rubocop:enable Style/ParallelAssignment | |
promise.then do |rendered_element| | |
button_nodes = find_element_jq_nodes(rendered_element, :button, element_id, nil, use_self) | |
# If no buttons exist, we'll get nil, if buttons do exist, we need a Ruby array before we can use find | |
jq_node = (button_nodes || []).to_a.find do |element| | |
if element_id | |
element[:id] == element_id | |
else | |
element.text == button_text | |
end | |
end | |
descriptor = (element_id || button_text) | |
raise_error = lambda do |msg| | |
markup = `#{get_jq_node(rendered_element).get[0]}.outerHTML` | |
raise "Cannot click button #{descriptor} because #{msg}, current markup is: #{markup}" | |
end | |
raise_error["no 'button' node exists under #{react_element}"] unless jq_node | |
is_disabled = lambda do |node| | |
node.has_attribute? 'disabled' | |
end | |
raise_error['the button is disabled'] if is_disabled[jq_node] | |
simulate_click jq_node, descriptor | |
promise | |
end | |
end | |
def simulate_change(jq_node, new_value, descriptor) | |
info_prefix = "Input #{descriptor} value change from #{jq_node.value} to #{new_value} -" | |
puts "#{info_prefix} Changing DOM value" if output_debug_messages | |
jq_node.value = new_value | |
puts "#{info_prefix} Triggering change event with React" if output_debug_messages | |
native_node = jq_node.get[0] | |
`React.addons.TestUtils.Simulate.change(#{native_node}, {target: {value: #{new_value}}})` | |
puts "#{info_prefix} Trigger complete" if output_debug_messages | |
end | |
def enter_text_value(new_value:, | |
element_id: nil, | |
element_name: nil, | |
use_self: false) | |
promise = get_unresolved_promise rendered_element | |
# With Opal, named arguments won't be found inside the block, so re-declare them here | |
# rubocop:disable Style/ParallelAssignment | |
new_value, element_id, use_self = [new_value, element_id, use_self] | |
# rubocop:enable Style/ParallelAssignment | |
promise.then do |rendered_element| | |
jq_node = find_element_jq_nodes rendered_element, :input, element_id, element_name, use_self = use_self | |
descriptor = (element_id || element_name) | |
# Browser always does strings | |
new_value = new_value.to_s | |
raise_error = lambda do |msg| | |
markup = `#{get_jq_node(rendered_element).get[0]}.outerHTML` | |
raise "Cannot change input #{descriptor} to #{new_value} because #{msg}, current markup is: #{markup}" | |
end | |
raise_error["no 'input' node exists under #{react_element}"] unless jq_node | |
is_disabled = lambda do |node| | |
node.has_attribute? 'disabled' | |
end | |
raise_error['the input text box is disabled'] if is_disabled[jq_node] | |
simulate_change jq_node, new_value, descriptor | |
promise | |
end | |
end | |
# event_promise - :update to wait for on update, :mount to wait for :mount | |
def choose_select_option(new_value:, | |
element_id: nil, | |
element_name: nil) | |
# With Opal, named arguments won't be found inside the block, so re-declare them here | |
# rubocop:disable Style/ParallelAssignment | |
new_value, element_id = [new_value, element_id] | |
# rubocop:enable Style/ParallelAssignment | |
stable_component_promise.then do |rendered_element| | |
jq_node = find_element_jq_nodes rendered_element, :select, element_id, element_name | |
descriptor = (element_id || element_name) | |
# Browser always does strings | |
new_value = new_value.to_s | |
raise_error = lambda do |msg| | |
markup = `#{get_jq_node(rendered_element).get[0]}.outerHTML` | |
raise "Cannot change select #{descriptor} to #{new_value} because #{msg}, current markup is: #{markup}" | |
end | |
raise_error["no 'select' node exists under #{react_element}"] unless jq_node | |
is_disabled = lambda do |node| | |
node.has_attribute? 'disabled' | |
end | |
raise_error['the select is disabled'] if is_disabled[jq_node] | |
option_element = jq_node.find "option[value=#{new_value}]" | |
raise_error["no option was found, possible values are #{jq_node.find('option').map(&:value)}"] unless option_element.any? | |
raise_error['the option is disabled'] if is_disabled[option_element] | |
simulate_change jq_node, new_value, descriptor | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@wied03, what's in your spec_helper? I also had to patch opal-rspec-rails to enable the .opal file extension for specs...