Geb - 如何删除 Geb 中的属性
Geb - How to remove attribute in Geb
我想为日期选择器设置值,它有属性 'readonly'。我尝试 removeAttr()
删除该属性,但出现如下错误:
Caught: groovy.lang.MissingMethodException: No signature of method: geb.navigator.NonEmptyNavigator.removeAttr() is applicable for argument types: (java.lang.String) values: [readonly]
如何删除 Geb 中的属性?
源代码:
<input ng-show="!date" class="ui-form-control ng-isolate-scope" name="date" placeholder="StartTime" ui-datepicker-trigger="" selected-date="date" readonly="readonly" type="text">
我的geb代码:
$('input', placeholder: 'StartTime').removeAttr('readonly')
谢谢大家
WebDriver 和 Geb 不允许您直接修改 DOM。
您需要通过 the js object to do that which will be even easier if your page has jQuery loaded into it thanks to Geb's jQuery integration 使用 javascript。
使用以下代码解决问题:
js.exec(
"document.getElementsByClassName('ui-form-control ng-isolate-scope')[0]" +
".removeAttribute('readonly')"
)
因为 OP 说这是一个 AngularJS 日期选择器,而我从未接触过 Angular,我自己不是前端人员,我想学习一些东西,现在我与您分享,无论它有什么价值。
这是一个 Geb 测试,它不使用任何 JS,而是纯粹通过 Geb 或 Selenium 从 Angular 日期选择器收集信息并与之交互。测试显示如何
- 通过
myNavigator.singleElement().getAttribute("value")
从日期选择器的文本字段中获取当前选择的日期(也适用于非活动控件),
- 通过打开日期选择器并在日历中找到突出显示的日期来获取当前选定的日期(当然,仅适用于活动控件),
- 相当乏味地与日期选择器交互,选择当年的圣诞节(12 月 25 日)
- 打开日期选择器,
- 点击当前月份以打开年份选择器,
- 点击十二月,再次有效关闭月份选择器,
- 点击第 25 天,再次有效关闭日期选择器,
- 最后通过阅读文本标签来检查是否设置了正确的日期,就像在示例 #1 中一样。
页数:
package de.scrum_master.Whosebug
import geb.Page
import geb.navigator.Navigator
import java.time.Month
import java.time.format.TextStyle
import static java.util.Calendar.*
class DatePickerPage extends Page {
static url = "https://material.angularjs.org/1.1.2/demo/datepicker"
static at = { heading == "Datepicker" }
static now = new GregorianCalendar()
static content = {
heading { $("h2 > span.md-breadcrumb-page.ng-binding").text() }
datePickerButtons { $("md-datepicker > button") }
datePickerInputFields { $(".md-datepicker-input") }
activeDatePicker(required: false) { $(".md-datepicker-calendar-pane.md-pane-open") }
selectedDate { activeDatePicker.$(".md-calendar-selected-date") }
currentMonthLabel {
activeDatePicker
.$("td.md-calendar-month-label", text: "${getMonthShort(now)} ${now.get(YEAR)}")
}
selectedMonth(required: false) { $("td.md-calendar-selected-date") }
}
String getDatePickerValue(Navigator datePickerInputField) {
datePickerInputField.singleElement().getAttribute("value")
}
Navigator getMonthLabel(Calendar calendar) {
$(".md-calendar-month-label", text: "${calendar.get(YEAR)}").closest("tbody")
.$("span", text: getMonthShort(calendar)).closest("td")
}
Navigator getDayOfMonthLabel(Calendar calendar) {
activeDatePicker
.$(".md-calendar-month-label", text: "${getMonthShort(calendar)} ${calendar.get(YEAR)}")
.closest("tbody")
.$("span", text: "${calendar.get(DAY_OF_MONTH)}")
.closest("td")
}
String getMonthShort(Calendar calendar) {
Month
.of(calendar.get(MONTH) + 1)
.getDisplayName(TextStyle.FULL, new Locale("en"))
.substring(0, 3)
}
}
测试:
package de.scrum_master.Whosebug
import geb.module.FormElement
import geb.spock.GebReportingSpec
import spock.lang.Unroll
import static java.util.Calendar.*
class DatePickerIT extends GebReportingSpec {
def now = new GregorianCalendar()
def xmas = new GregorianCalendar(now.get(YEAR), 12 - 1, 25)
@Unroll
def "Get selected date from Angular date label"() {
when: "a date picker on the Angular demo page is chosen"
DatePickerPage page = to DatePickerPage
def datePickerInputField = page.datePickerInputFields[datePickerIndex]
then: "that date picker instance is (in-)active as expected"
datePickerInputField.module(FormElement).enabled == isEnabled
when: "the active date is read from the date picker's text input field"
String activeDateString = page.getDatePickerValue(datePickerInputField)
String todayString = "${now.get(MONTH) + 1}/${now.get(DAY_OF_MONTH)}/${now.get(YEAR)}"
then: "it is today"
todayString == activeDateString
where:
datePickerIndex << [0, 1, 2, 3, 4, 5, 6, 7, 8]
isEnabled << [true, false, true, true, true, true, true, true, true]
}
@Unroll
def "Get selected date from opened Angular date picker"() {
when: "a date picker on the Angular demo page is chosen"
DatePickerPage page = to DatePickerPage
def datePickerButton = page.datePickerButtons[datePickerIndex]
then: "that date picker instance is active (not greyed out)"
datePickerButton.module(FormElement).enabled
when: "the calendar button for the date picker is clicked"
datePickerButton.click()
then: "the date picker pop-up opens, displaying the current month"
waitFor 3, { page.activeDatePicker.displayed }
when: "the active date's timestamp is read from the highlighted day in the calendar"
def selectedDateMillis = page.selectedDate.attr("data-timestamp") as long
def sinceMidnightMillis = now.getTimeInMillis() - selectedDateMillis
then: "it is today"
sinceMidnightMillis >= 0
sinceMidnightMillis < 24 * 60 * 60 * 1000
where:
datePickerIndex << [0, 2, 4, 5, 6, 7, 8]
}
def "Set date in Angular date picker"() {
when: "the first date picker's calendar button on the Angular demo page is clicked"
DatePickerPage page = to DatePickerPage
page.datePickerButtons[0].click()
then: "the date picker pop-up opens, displaying the current month"
waitFor 3, { page.activeDatePicker.displayed }
when: "the current month label is clicked"
page.currentMonthLabel.click()
then: "the month selection page opens"
waitFor 3, { page.selectedMonth.displayed }
page.selectedMonth.text() == page.getMonthShort(now)
when: "December for the current year is selected"
page.getMonthLabel(xmas).click()
then: "the month selection page closes again"
waitFor 3, { !page.selectedMonth.displayed }
when: "Xmas Day (25) is selected on the month calendar"
page.getDayOfMonthLabel(xmas).click()
then: "the date picker pop-up closes again"
waitFor 3, { !page.activeDatePicker.displayed }
when: "the active date is read from the date picker's text input field"
String activeDateString = page.getDatePickerValue(page.datePickerInputFields[0])
String xmasDayString = "${xmas.get(MONTH) + 1}/${xmas.get(DAY_OF_MONTH)}/${xmas.get(YEAR)}"
then: "it is Xmas Day of the current year"
xmasDayString == activeDateString
}
}
这种方法的优势是显而易见的:您仅以用户 would/could 也采用的方式与页面交互,从而避免以用户不可能的方式操作页面(这会导致糟糕的测试)。
更新:我将代码重构为使用页面对象。
我想为日期选择器设置值,它有属性 'readonly'。我尝试 removeAttr()
删除该属性,但出现如下错误:
Caught: groovy.lang.MissingMethodException: No signature of method: geb.navigator.NonEmptyNavigator.removeAttr() is applicable for argument types: (java.lang.String) values: [readonly]
如何删除 Geb 中的属性?
源代码:
<input ng-show="!date" class="ui-form-control ng-isolate-scope" name="date" placeholder="StartTime" ui-datepicker-trigger="" selected-date="date" readonly="readonly" type="text">
我的geb代码:
$('input', placeholder: 'StartTime').removeAttr('readonly')
谢谢大家
WebDriver 和 Geb 不允许您直接修改 DOM。
您需要通过 the js object to do that which will be even easier if your page has jQuery loaded into it thanks to Geb's jQuery integration 使用 javascript。
使用以下代码解决问题:
js.exec(
"document.getElementsByClassName('ui-form-control ng-isolate-scope')[0]" +
".removeAttribute('readonly')"
)
因为 OP 说这是一个 AngularJS 日期选择器,而我从未接触过 Angular,我自己不是前端人员,我想学习一些东西,现在我与您分享,无论它有什么价值。
这是一个 Geb 测试,它不使用任何 JS,而是纯粹通过 Geb 或 Selenium 从 Angular 日期选择器收集信息并与之交互。测试显示如何
- 通过
myNavigator.singleElement().getAttribute("value")
从日期选择器的文本字段中获取当前选择的日期(也适用于非活动控件), - 通过打开日期选择器并在日历中找到突出显示的日期来获取当前选定的日期(当然,仅适用于活动控件),
- 相当乏味地与日期选择器交互,选择当年的圣诞节(12 月 25 日)
- 打开日期选择器,
- 点击当前月份以打开年份选择器,
- 点击十二月,再次有效关闭月份选择器,
- 点击第 25 天,再次有效关闭日期选择器,
- 最后通过阅读文本标签来检查是否设置了正确的日期,就像在示例 #1 中一样。
页数:
package de.scrum_master.Whosebug
import geb.Page
import geb.navigator.Navigator
import java.time.Month
import java.time.format.TextStyle
import static java.util.Calendar.*
class DatePickerPage extends Page {
static url = "https://material.angularjs.org/1.1.2/demo/datepicker"
static at = { heading == "Datepicker" }
static now = new GregorianCalendar()
static content = {
heading { $("h2 > span.md-breadcrumb-page.ng-binding").text() }
datePickerButtons { $("md-datepicker > button") }
datePickerInputFields { $(".md-datepicker-input") }
activeDatePicker(required: false) { $(".md-datepicker-calendar-pane.md-pane-open") }
selectedDate { activeDatePicker.$(".md-calendar-selected-date") }
currentMonthLabel {
activeDatePicker
.$("td.md-calendar-month-label", text: "${getMonthShort(now)} ${now.get(YEAR)}")
}
selectedMonth(required: false) { $("td.md-calendar-selected-date") }
}
String getDatePickerValue(Navigator datePickerInputField) {
datePickerInputField.singleElement().getAttribute("value")
}
Navigator getMonthLabel(Calendar calendar) {
$(".md-calendar-month-label", text: "${calendar.get(YEAR)}").closest("tbody")
.$("span", text: getMonthShort(calendar)).closest("td")
}
Navigator getDayOfMonthLabel(Calendar calendar) {
activeDatePicker
.$(".md-calendar-month-label", text: "${getMonthShort(calendar)} ${calendar.get(YEAR)}")
.closest("tbody")
.$("span", text: "${calendar.get(DAY_OF_MONTH)}")
.closest("td")
}
String getMonthShort(Calendar calendar) {
Month
.of(calendar.get(MONTH) + 1)
.getDisplayName(TextStyle.FULL, new Locale("en"))
.substring(0, 3)
}
}
测试:
package de.scrum_master.Whosebug
import geb.module.FormElement
import geb.spock.GebReportingSpec
import spock.lang.Unroll
import static java.util.Calendar.*
class DatePickerIT extends GebReportingSpec {
def now = new GregorianCalendar()
def xmas = new GregorianCalendar(now.get(YEAR), 12 - 1, 25)
@Unroll
def "Get selected date from Angular date label"() {
when: "a date picker on the Angular demo page is chosen"
DatePickerPage page = to DatePickerPage
def datePickerInputField = page.datePickerInputFields[datePickerIndex]
then: "that date picker instance is (in-)active as expected"
datePickerInputField.module(FormElement).enabled == isEnabled
when: "the active date is read from the date picker's text input field"
String activeDateString = page.getDatePickerValue(datePickerInputField)
String todayString = "${now.get(MONTH) + 1}/${now.get(DAY_OF_MONTH)}/${now.get(YEAR)}"
then: "it is today"
todayString == activeDateString
where:
datePickerIndex << [0, 1, 2, 3, 4, 5, 6, 7, 8]
isEnabled << [true, false, true, true, true, true, true, true, true]
}
@Unroll
def "Get selected date from opened Angular date picker"() {
when: "a date picker on the Angular demo page is chosen"
DatePickerPage page = to DatePickerPage
def datePickerButton = page.datePickerButtons[datePickerIndex]
then: "that date picker instance is active (not greyed out)"
datePickerButton.module(FormElement).enabled
when: "the calendar button for the date picker is clicked"
datePickerButton.click()
then: "the date picker pop-up opens, displaying the current month"
waitFor 3, { page.activeDatePicker.displayed }
when: "the active date's timestamp is read from the highlighted day in the calendar"
def selectedDateMillis = page.selectedDate.attr("data-timestamp") as long
def sinceMidnightMillis = now.getTimeInMillis() - selectedDateMillis
then: "it is today"
sinceMidnightMillis >= 0
sinceMidnightMillis < 24 * 60 * 60 * 1000
where:
datePickerIndex << [0, 2, 4, 5, 6, 7, 8]
}
def "Set date in Angular date picker"() {
when: "the first date picker's calendar button on the Angular demo page is clicked"
DatePickerPage page = to DatePickerPage
page.datePickerButtons[0].click()
then: "the date picker pop-up opens, displaying the current month"
waitFor 3, { page.activeDatePicker.displayed }
when: "the current month label is clicked"
page.currentMonthLabel.click()
then: "the month selection page opens"
waitFor 3, { page.selectedMonth.displayed }
page.selectedMonth.text() == page.getMonthShort(now)
when: "December for the current year is selected"
page.getMonthLabel(xmas).click()
then: "the month selection page closes again"
waitFor 3, { !page.selectedMonth.displayed }
when: "Xmas Day (25) is selected on the month calendar"
page.getDayOfMonthLabel(xmas).click()
then: "the date picker pop-up closes again"
waitFor 3, { !page.activeDatePicker.displayed }
when: "the active date is read from the date picker's text input field"
String activeDateString = page.getDatePickerValue(page.datePickerInputFields[0])
String xmasDayString = "${xmas.get(MONTH) + 1}/${xmas.get(DAY_OF_MONTH)}/${xmas.get(YEAR)}"
then: "it is Xmas Day of the current year"
xmasDayString == activeDateString
}
}
这种方法的优势是显而易见的:您仅以用户 would/could 也采用的方式与页面交互,从而避免以用户不可能的方式操作页面(这会导致糟糕的测试)。
更新:我将代码重构为使用页面对象。