Last active
February 4, 2022 01:06
-
-
Save mgrybyk/a2fec1b0dae7dd1ecafbc4e39817d351 to your computer and use it in GitHub Desktop.
WebdriverIO snippets
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
const lang = 'en' | |
describe('element ui date picker', () => { | |
it('set current date +60 days', () => { | |
browser.url('https://element.eleme.io/#/en-US/component/date-picker') | |
const datePickerInput = $('.el-date-editor>input') | |
expect(datePickerInput).toBeClickable() | |
const datePicker = new DatePickerElement(datePickerInput) | |
const dateToBeSet = currentDateShift(60) // current date + 60 days | |
datePicker.setValue(dateToBeSet) | |
expect(datePickerInput).toHaveValue(formatDate(dateToBeSet)) | |
browser.pause(2000) // demo purposes | |
}) | |
}) | |
// date helpers | |
const timeZoneDate = (date) => new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000) | |
const formatDate = (date) => timeZoneDate(date).toISOString().split('T')[0] | |
const dateNoTime = (date) => new Date(formatDate(date)) | |
const dateShift = (shift, date) => new Date(dateNoTime(date).getTime() + shift * 24 * 60 * 60 * 1000) | |
const currentDateShift = (shift) => dateShift(shift, new Date()) | |
// every date picker in Element UI is a dropdown | |
class CustomDropdownElement { | |
constructor(rootSelector, toggleSelectorOrElement) { | |
this.rootSelector = rootSelector | |
this.toggleSelectorOrElement = toggleSelectorOrElement | |
} | |
get $toggle() { | |
return typeof this.toggleSelectorOrElement === 'string' ? $(this.toggleSelectorOrElement) : this.toggleSelectorOrElement | |
} | |
get $dropdown() { | |
return $(this.rootSelector) | |
} | |
open() { | |
this.$toggle.click({ wait: true }) | |
this.$dropdown.waitForClickable() | |
this.waitForAnimation() | |
} | |
/** | |
* show/hide timeout https://element.eleme.io/#/en-US/component/dropdown | |
*/ | |
waitForAnimation() { | |
browser.pause(150) | |
} | |
} | |
// implementation os single date picker, there are also other types | |
class DatePickerElement extends CustomDropdownElement { | |
constructor(inputSelectorOrElement) { | |
const dropdownSelector = '.el-date-picker.el-popper[x-placement]' | |
super(dropdownSelector, inputSelectorOrElement) | |
this.calendarElement = new DatePickerCalendarElement(dropdownSelector) | |
} | |
setValue(date) { | |
this.open() | |
const currentMonth = this.calendarElement.getCurrentMonth(DatePickerElement.getMonthFn) | |
const currentYear = this.calendarElement.getCurrentYear(DatePickerElement.getYearFn) | |
// change month if needed | |
if (currentMonth !== date.getMonth()) { | |
let directionButton | |
if (currentYear !== date.getFullYear()) { | |
directionButton = currentYear > date.getFullYear() ? this.calendarElement.$prevMonth : this.calendarElement.$nextMonth | |
} else { | |
directionButton = currentMonth > date.getMonth() ? this.calendarElement.$prevMonth : this.calendarElement.$nextMonth | |
} | |
browser.waitUntil(() => { | |
directionButton.click() | |
return ( | |
this.calendarElement.getCurrentMonth(DatePickerElement.getMonthFn) === date.getMonth() && | |
this.calendarElement.getCurrentYear(DatePickerElement.getYearFn) === date.getFullYear() | |
) | |
}) | |
} | |
// set day | |
this.calendarElement.getDayOfMonthElement(date.getDate()).click() | |
this.$dropdown.waitForExist({ reverse: true }) | |
} | |
static getYearFn = ($header) => DatePickerElement.getYearOrMonthFn($header, 1) | |
static getMonthFn = ($header) => DatePickerElement.getYearOrMonthFn($header, 2) | |
static getYearOrMonthFn = ($header, idx) => $header.$(`span:nth-of-type(${idx})`).getText().trim() | |
} | |
// base part of every date picker | |
class DatePickerCalendarElement { | |
constructor(rootSelector) { | |
this.rootSelector = rootSelector | |
} | |
get $root() { | |
return $(this.rootSelector) | |
} | |
get $header() { | |
return this.$root.$('[class*="picker__header"]') | |
} | |
get $prevMonth() { | |
return this.$header.$('.el-icon-arrow-left') | |
} | |
get $nextMonth() { | |
return this.$header.$('.el-icon-arrow-right') | |
} | |
get $selectedDay() { | |
return this.$root.$('.el-date-table .current') | |
} | |
getDayOfMonthElement(day) { | |
return this.$root.$(`.//table[@class="el-date-table"]//td[contains(@class, "available")]//*[normalize-space(text()) = "${day}"]`) | |
} | |
getCurrentMonth(getMonthText) { | |
let result = -1 | |
browser.waitUntil( | |
() => { | |
const month = getMonthText(this.$header) | |
result = monthsLocalizedArray(lang).indexOf(month) | |
return result > -1 | |
}, | |
{ timeoutMsg: 'failed to get current month from calendar' } | |
) | |
return result | |
} | |
getCurrentYear(getYearText) { | |
let result = -1 | |
browser.waitUntil( | |
() => { | |
result = Number.parseInt(getYearText(this.$header)) | |
return Number.isInteger(result) | |
}, | |
{ timeoutMsg: 'failed to get current year from calendar' } | |
) | |
return result | |
} | |
} | |
/** | |
* full-icu package has to be installed to make `Date.toLocaleString` work on some systems | |
* see https://stackoverflow.com/questions/23199909/using-tolocalestring-in-node-js/23200062#23200062 | |
*/ | |
const monthsLocalizedArray = function (locale = 'en') { | |
const result = [] | |
for (let i = 0; i < 12; i++) { | |
result.push(new Date(2010, i).toLocaleString(locale, { month: 'long' })) | |
} | |
return result | |
} |
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
const lang = 'en' | |
describe('element ui date picker', () => { | |
it('set current date +60 days', () => { | |
browser.url('https://element.eleme.io/#/en-US/component/date-picker') | |
const datePickerInput = $('.el-date-editor>input') | |
expect(datePickerInput).toBeClickable() | |
const datePicker = new DatePickerElement(datePickerInput) | |
const dateToBeSet = currentDateShift(60) // current date + 60 days | |
datePicker.setValue(dateToBeSet) | |
expect(datePickerInput).toHaveValue(formatDate(dateToBeSet)) | |
browser.pause(2000) // demo purposes | |
}) | |
}) | |
// date helpers | |
const timeZoneDate = (date: Date) => new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000) | |
const formatDate = (date: Date) => timeZoneDate(date).toISOString().split('T')[0] | |
const dateNoTime = (date: Date) => new Date(formatDate(date)) | |
const dateShift = (shift: number, date: Date) => new Date(dateNoTime(date).getTime() + shift * 24 * 60 * 60 * 1000) | |
const currentDateShift = (shift: number) => dateShift(shift, new Date()) | |
// every date picker in Element UI is a dropdown | |
abstract class CustomDropdownElement { | |
readonly rootSelector: string | |
readonly toggleSelectorOrElement: string | WebdriverIO.Element | |
constructor(rootSelector: string, toggleSelectorOrElement: string | WebdriverIO.Element) { | |
this.rootSelector = rootSelector | |
this.toggleSelectorOrElement = toggleSelectorOrElement | |
} | |
protected get $toggle() { | |
return typeof this.toggleSelectorOrElement === 'string' ? $(this.toggleSelectorOrElement) : this.toggleSelectorOrElement | |
} | |
protected get $dropdown() { | |
return $(this.rootSelector) | |
} | |
public open() { | |
this.$toggle.click({ wait: true }) | |
this.$dropdown.waitForClickable() | |
this.waitForAnimation() | |
} | |
/** | |
* show/hide timeout https://element.eleme.io/#/en-US/component/dropdown | |
*/ | |
waitForAnimation() { | |
browser.pause(150) | |
} | |
} | |
// implementation os single date picker, there are also other types | |
class DatePickerElement extends CustomDropdownElement { | |
private calendarElement: DatePickerCalendarElement | |
constructor(inputSelectorOrElement: string | WebdriverIO.Element) { | |
const dropdownSelector = '.el-date-picker.el-popper[x-placement]' | |
super(dropdownSelector, inputSelectorOrElement) | |
this.calendarElement = new DatePickerCalendarElement(dropdownSelector) | |
} | |
public setValue(date: Date) { | |
this.open() | |
const currentMonth = this.calendarElement.getCurrentMonth(DatePickerElement.getMonthFn) | |
const currentYear = this.calendarElement.getCurrentYear(DatePickerElement.getYearFn) | |
// change month if needed | |
if (currentMonth !== date.getMonth()) { | |
let directionButton: WebdriverIO.Element | |
if (currentYear !== date.getFullYear()) { | |
directionButton = currentYear > date.getFullYear() ? this.calendarElement.$prevMonth : this.calendarElement.$nextMonth | |
} else { | |
directionButton = currentMonth > date.getMonth() ? this.calendarElement.$prevMonth : this.calendarElement.$nextMonth | |
} | |
browser.waitUntil(() => { | |
directionButton.click() | |
return ( | |
this.calendarElement.getCurrentMonth(DatePickerElement.getMonthFn) === date.getMonth() && | |
this.calendarElement.getCurrentYear(DatePickerElement.getYearFn) === date.getFullYear() | |
) | |
}) | |
} | |
// set day | |
this.calendarElement.getDayOfMonthElement(date.getDate()).click() | |
this.$dropdown.waitForExist({ reverse: true }) | |
} | |
private static getYearFn = ($header: WebdriverIO.Element) => DatePickerElement.getYearOrMonthFn($header, 1) | |
private static getMonthFn = ($header: WebdriverIO.Element) => DatePickerElement.getYearOrMonthFn($header, 2) | |
private static getYearOrMonthFn = ($header: WebdriverIO.Element, idx: number) => $header.$(`span:nth-of-type(${idx})`).getText().trim() | |
} | |
// base part of every date picker | |
class DatePickerCalendarElement { | |
private rootSelector: string | |
constructor(rootSelector: string) { | |
this.rootSelector = rootSelector | |
} | |
private get $root() { | |
return $(this.rootSelector) | |
} | |
private get $header() { | |
return this.$root.$('[class*="picker__header"]') | |
} | |
get $prevMonth() { | |
return this.$header.$('.el-icon-arrow-left') | |
} | |
get $nextMonth() { | |
return this.$header.$('.el-icon-arrow-right') | |
} | |
get $selectedDay() { | |
return this.$root.$('.el-date-table .current') | |
} | |
getDayOfMonthElement(day: number) { | |
return this.$root.$(`.//table[@class="el-date-table"]//td[contains(@class, "available")]//*[normalize-space(text()) = "${day}"]`) | |
} | |
getCurrentMonth(getMonthText: ($header: WebdriverIO.Element) => string) { | |
let result = -1 | |
browser.waitUntil( | |
() => { | |
const month = getMonthText(this.$header) | |
result = monthsLocalizedArray(lang).indexOf(month) | |
return result > -1 | |
}, | |
{ timeoutMsg: 'failed to get current month from calendar' } | |
) | |
return result | |
} | |
getCurrentYear(getYearText: ($header: WebdriverIO.Element) => string) { | |
let result = -1 | |
browser.waitUntil( | |
() => { | |
result = Number.parseInt(getYearText(this.$header)) | |
return Number.isInteger(result) | |
}, | |
{ timeoutMsg: 'failed to get current year from calendar' } | |
) | |
return result | |
} | |
} | |
/** | |
* full-icu package has to be installed to make `Date.toLocaleString` work on some systems | |
* see https://stackoverflow.com/questions/23199909/using-tolocalestring-in-node-js/23200062#23200062 | |
*/ | |
const monthsLocalizedArray = function (locale = 'en') { | |
const result = [] | |
for (let i = 0; i < 12; i++) { | |
result.push(new Date(2010, i).toLocaleString(locale, { month: 'long' })) | |
} | |
return result | |
} |
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
it('emulate file drop event', () => { | |
browser.url('https://the-internet.herokuapp.com/upload') | |
const fileInput = $('input[type="file"]') | |
expect(fileInput).toExist() | |
fileInput.setValue('/Users/m/sources/multiforce-backoffice-site/foo.pdf') | |
const dropArea = $('#drag-drop-upload') | |
expect(dropArea).toBeVisible() | |
expect(dropArea).not.toHaveChildren() | |
browser.execute((fd) => { | |
function fireMouseEvent(type, relatedTarget) { | |
const evt = new MouseEvent(type, { relatedTarget, bubbles: true }) | |
evt.dataTransfer = { ...new DataTransfer() } | |
evt.dataTransfer.files = document.querySelector('input[type="file"]').files | |
relatedTarget.dispatchEvent(evt) | |
} | |
fireMouseEvent('drop', fd) | |
}, dropArea) | |
expect(dropArea).toHaveChildren(1) | |
browser.pause(2000) // demo | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment