简体   繁体   English

Rspec&Capybara:使用jQuery将焦点设置为元素不适用`:focus` CSS

[英]Rspec & Capybara: Setting focus to an element using jQuery doesn't apply `:focus` CSS

I have jump links for blind and keyboard users in my webpage which are moved out of the viewport to hide them visually; 我在我的网页中有盲人和键盘用户的跳转链接,这些用户被移出视口以便在视觉上隐藏它们; when they gain focus, they are moved into the viewport. 当他们获得焦点时,他们会被移动到视口中。

I want to test this behaviour using RSpec and Capybara, but it somehow doesn't work. 我想使用RSpec和Capybara测试这种行为,但它不知何故不起作用。

  it 'moves the focus to the navigation when activating the corresponding link', js: true do
    expect(page).not_to have_css '#main:focus'
    page.evaluate_script "$('#jump_to_content > a').focus()"
    click_link 'Jump to content'
    expect(page).to have_css '#main:focus'
  end

The JavaScript in evaluate_script doesn't seem to be executed properly. evaluate_script中的JavaScript似乎没有正确执行。 I tried the same JS ( $('#jump_to_content > a').focus() ) in the Chrome console, and I'm a bit unsure about the result, because while in the console, the link doesn't appear, but when clicking into the browser view, it appears for a part of a second and disappears again (it disappears because it doesn't have the focus anymore then). 我在Chrome控制台中尝试了相同的JS( $('#jump_to_content > a').focus() ),我对结果有点不确定,因为在控制台中,链接没有出现,但是当点击进入浏览器视图时,它会显示一段时间并再次消失(它会消失,因为它不再具有焦点)。 In my opinion it should be displayed directly after executing the JS. 在我看来,它应该在执行JS后直接显示。

This makes me a bit insecure about all this. 这让我对这一切有点不安全。 Any help is highly appreciated. 任何帮助都非常感谢。

Update 更新

I meanwhile have come to the conclusion that the behaviour of Chrome is normal: focus is kept in the console, so the element in fact doesn't really receive focus and doesn't show. 我同时得出结论,Chrome的行为是正常的:焦点保留在控制台中,因此该元素实际上并没有真正获得焦点而且没有显示。

I have also come to the conclusion that Capybara doesn't seem to be able to handle focusing an element (and applying :focus styles) properly. 我还得出结论,Capybara似乎无法正确处理一个元素(并应用:focus样式)。

I have created the following CSS rules: 我创建了以下CSS规则:

a#jump_to_navigation color: black #jump_to_navigation颜色:黑色

&:focus
  color: red

For testing this, I have set up this very specific test: 为了测试这个,我设置了这个非常具体的测试:

visit root_path

selector = 'a#jump_to_navigation'

# Initial style
expect(page.evaluate_script('document.activeElement.id')).to eq ''                  # Make sure the link isn't focused yet
expect(page.evaluate_script("$('#{selector}').css('color')")).to  eq 'rgb(0, 0, 0)' # Color initially is black

# Set focus
page.evaluate_script("$('#{selector}').focus()")

# Focused style
expect(page.evaluate_script('document.activeElement.id')).to eq 'jump_to_navigation'  # Make sure the link is focused now
expect(page.evaluate_script("$('#{selector}').css('color')")).to  eq 'rgb(255, 0, 0)' # Color is now red

The test breaks like this: 测试打破了这样:

1) Navigation jump links visually displays them only on focus
   Failure/Error: expect(page.evaluate_script("$('#{selector}').css('color')")).to  eq 'rgb(255, 0, 0)' # Color is now red

     expected: "rgb(255, 0, 0)"
          got: "rgb(0, 0, 0)"

     (compared using ==)

So the focus is set properly, but the :focus styles aren't applied. 因此焦点设置正确,但不应用:focus样式。 I guess this is a problem with PhantomJS? 我猜这是PhantomJS的一个问题?

I'd be very happy to find a solution around this problem. 我很乐意找到解决这个问题的方法。

This has worked for me to get an element visible on the page first. 这对我有用,首先在页面上显示一个元素。 I've had to use this as a precursor to some drag and drop tests. 我不得不使用它作为一些拖放测试的前身。

page.execute_script("document.getElementById('foo').scrollIntoView()")

I found a workaround by using JavaScript to add/remove a class (in my case, .sr-only ) instead of relying on CSS' :hover mechanism. 我找到了一种解决方法,通过使用JavaScript来添加/删除一个类(在我的情况下, .sr-only )而不是依赖于CSS :hover机制。

visit root_path

selector = '#jump_to_navigation'

expect(page.evaluate_script('document.activeElement.id')).to eq '' # Make sure the link isn't focused yet

# Initial (hidden) position
expect(page.evaluate_script("$('#{selector}')[0].className")).to eq 'sr-only' # Make sure the link has sr-only class

# Set focus
page.evaluate_script("$('#{selector}').focus()")
expect('#' + page.evaluate_script('document.activeElement.id')).to eq selector # Make sure the link is focused now

# Displayed position
expect(page.evaluate_script("$('#{selector}')[0].className")).to eq '' # Make sure the link doesn't have sr-only class

# Remove focus
page.evaluate_script("$('#{selector}').blur()")
expect(page.evaluate_script('document.activeElement.id')).to eq '' # Make sure the link is focused now

# Hidden position again
expect(page.evaluate_script("$('#{selector}')[0].className")).to eq 'sr-only' # Make sure the link has sr-only class

This seems to work. 这似乎有效。 I didn't check whether this way also CSS changes are recognised by Capybara, but for my case, it's enough. 我没有检查这种方式是否也被Capybara识别出来,但对于我的情况来说,这已经足够了。

Important: By the way, you should use execute_script instead of evaluate_script , as the latter one has a huge performance impact ! 重要提示:顺便说一句,您应该使用execute_script而不是evaluate_script ,因为后者会对性能产生巨大影响

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM