处理多个 Capybara React-select 下拉列表?
Dealing with Multiple Capybara React-select dropdowns?
所以当使用 Capybara 和 Chromedriver 自动化网页时,我有一个包含多个下拉菜单(具有相同选择)的页面。
它们都是 react-select(我有一个帮助文件)。遗憾的是,它们都有相同的标签文本(但标签 ID 不同……但我认为 page.select
不适用于标签 ID)。
我考虑过在 react-select 上做一个 page.all?然后只是通过数组?这可能吗?
react-select 看起来很标准,我意识到 span 有一个 id 但是 selecting 对我的 react-selects 不起作用已经说出来了。:
<div class="Select-control">
<span class="Select-multi-value-wrapper" id="react-select-6--value">
<div class="Select-placeholder">Select...</div>
<div class="Select-input" style="display: inline-block;">
<input role="combobox" aria-expanded="false" aria-owns="" aria-haspopup="false" aria-activedescendant="react-select-6--value" value="" style="width: 5px; box-sizing: content-box;">
<div style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre;"></div>
</div>
</span>
<span class="Select-arrow-zone"><span class="Select-arrow"></span></span>
</div>
我可以通过 page.all 将其拉入吗?我的反应助手是这样做的:
module CapybaraReactHelper
def capybara_react_select(selector, label)
within selector do
find('.Select-control').click
expect(page).to have_css('.Select-menu-outer') # options should now be available
expect(page).to have_css('.Select-option', text: label)
find('.Select-option', text: label).click
end
end
end
有什么想法吗?
谢谢!
在 .Select-multi-value-wrapper
上通过 id
选择无效,因为 span
不是 react-select 组件的顶级标签。使用 react-select 和 Capybara 通常很困难,因为 Capybara 表单助手无法使用 react-select 的自定义标记和行为。
正如您所提到的,您可以通过使用具有作用域 within
块和 page.all()
的现有助手版本来解决此问题。例如:
# helper
def react_select_capybara(selector, option)
within selector do
find('.Select-arrow-zone').click
expect(page).to have_css('.Select-menu-outer')
find('.Select-option', text: option).click
expect(page).to have_css('.Select-value-label', text: option)
end
end
# usage
given(:select_values) { ['Grace Hopper', 'Ada Lovelace'] }
...
react_selects = page.all('.Select')
select_values.each do |select_value, i|
react_select_capybara(react_selects[i], select_value)
end
虽然这会起作用,但它很脆弱 - 它依赖于页面上 react-selects 的隐式排序。更健壮的设置会向每个 react-select 组件传递一个自定义类名,以在您的测试中唯一地标识它。来自 react-select docs on custom classnames:
You can provide a custom className prop to the component, which will be added to the base .Select className for the outer container.
实现可能如下所示:
# JSX
<ReactSelect className="js-select-user-form-1" ... />
<ReactSelect className="js-select-user-form-2" ... />
# Spec
react_select_capybara(".js-select-user-form-1", 'Grace Hopper')
react_select_capybara(".js-select-user-form-2", 'Ada Lovelace')
page.select
不适用于此,因为它仅适用于 HTML <select>
元素。这是一个 JS 驱动的小部件,而不是 HTML <select>
元素。
如果您只是自动化页面(而不是测试应用程序),那么使用 JS(通过 execute_script
)设置隐藏的 <input>
的值可能会更容易。
如果你正在测试一个应用程序,那么你可以使用 page.all
来收集所有的 react-selects 并单步执行,只要 selecting 来自任何 react- select 不会替换页面上的任何其他元素(这会让您留下过时的元素)。
如果这不能提供足够的信息来解决您的问题,而您的真正问题是尝试从中选择特定的反应-select 到 select,那么请添加足够的 HTML 到你的问题,这样我们就可以看到你试图从中选择的小部件之间存在什么实际差异(例如 2 个不同的 react-select 元素)
所以当使用 Capybara 和 Chromedriver 自动化网页时,我有一个包含多个下拉菜单(具有相同选择)的页面。
它们都是 react-select(我有一个帮助文件)。遗憾的是,它们都有相同的标签文本(但标签 ID 不同……但我认为 page.select
不适用于标签 ID)。
我考虑过在 react-select 上做一个 page.all?然后只是通过数组?这可能吗?
react-select 看起来很标准,我意识到 span 有一个 id 但是 selecting 对我的 react-selects 不起作用已经说出来了。:
<div class="Select-control">
<span class="Select-multi-value-wrapper" id="react-select-6--value">
<div class="Select-placeholder">Select...</div>
<div class="Select-input" style="display: inline-block;">
<input role="combobox" aria-expanded="false" aria-owns="" aria-haspopup="false" aria-activedescendant="react-select-6--value" value="" style="width: 5px; box-sizing: content-box;">
<div style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre;"></div>
</div>
</span>
<span class="Select-arrow-zone"><span class="Select-arrow"></span></span>
</div>
我可以通过 page.all 将其拉入吗?我的反应助手是这样做的:
module CapybaraReactHelper
def capybara_react_select(selector, label)
within selector do
find('.Select-control').click
expect(page).to have_css('.Select-menu-outer') # options should now be available
expect(page).to have_css('.Select-option', text: label)
find('.Select-option', text: label).click
end
end
end
有什么想法吗?
谢谢!
在 .Select-multi-value-wrapper
上通过 id
选择无效,因为 span
不是 react-select 组件的顶级标签。使用 react-select 和 Capybara 通常很困难,因为 Capybara 表单助手无法使用 react-select 的自定义标记和行为。
正如您所提到的,您可以通过使用具有作用域 within
块和 page.all()
的现有助手版本来解决此问题。例如:
# helper
def react_select_capybara(selector, option)
within selector do
find('.Select-arrow-zone').click
expect(page).to have_css('.Select-menu-outer')
find('.Select-option', text: option).click
expect(page).to have_css('.Select-value-label', text: option)
end
end
# usage
given(:select_values) { ['Grace Hopper', 'Ada Lovelace'] }
...
react_selects = page.all('.Select')
select_values.each do |select_value, i|
react_select_capybara(react_selects[i], select_value)
end
虽然这会起作用,但它很脆弱 - 它依赖于页面上 react-selects 的隐式排序。更健壮的设置会向每个 react-select 组件传递一个自定义类名,以在您的测试中唯一地标识它。来自 react-select docs on custom classnames:
You can provide a custom className prop to the component, which will be added to the base .Select className for the outer container.
实现可能如下所示:
# JSX
<ReactSelect className="js-select-user-form-1" ... />
<ReactSelect className="js-select-user-form-2" ... />
# Spec
react_select_capybara(".js-select-user-form-1", 'Grace Hopper')
react_select_capybara(".js-select-user-form-2", 'Ada Lovelace')
page.select
不适用于此,因为它仅适用于 HTML <select>
元素。这是一个 JS 驱动的小部件,而不是 HTML <select>
元素。
如果您只是自动化页面(而不是测试应用程序),那么使用 JS(通过 execute_script
)设置隐藏的 <input>
的值可能会更容易。
如果你正在测试一个应用程序,那么你可以使用 page.all
来收集所有的 react-selects 并单步执行,只要 selecting 来自任何 react- select 不会替换页面上的任何其他元素(这会让您留下过时的元素)。
如果这不能提供足够的信息来解决您的问题,而您的真正问题是尝试从中选择特定的反应-select 到 select,那么请添加足够的 HTML 到你的问题,这样我们就可以看到你试图从中选择的小部件之间存在什么实际差异(例如 2 个不同的 react-select 元素)