test(time-picker): [time-picker] optimize time-picker e2e test (#1075)

This commit is contained in:
Kagol 2023-12-11 09:33:48 +08:00 committed by GitHub
parent c8b1913762
commit c9ce362694
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 159 additions and 133 deletions

View File

@ -4,38 +4,17 @@ test('时间选择器基本用法', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#basic-usage')
const preview = page.locator('#preview')
const timePicker = preview.locator('.tiny-date-editor > input')
const timeSelect = page.locator('.tiny-time-panel')
const hourSelect = timeSelect.locator('.tiny-scrollbar').first()
const minSelect = timeSelect.locator('.tiny-scrollbar').nth(1)
const secondSelect = timeSelect.locator('.tiny-scrollbar').nth(2)
// 测试滚动选择时间
const timePicker = page.getByRole('textbox', { name: '18:42:00' }).first()
await page.getByRole('textbox', { name: '18:40:00' }).first().click()
await page.getByRole('listitem').filter({ hasText: '42' }).first().click()
await page.getByRole('button', { name: '确定' }).click()
await expect(timePicker).toBeVisible()
// 测试非法输入是否赋予默认值
await expect(timePicker).toHaveValue('18:40:00')
await timePicker.click()
await expect(timeSelect).toBeVisible()
await timePicker.fill('inValidInput')
await timePicker.press('Enter')
await expect(timePicker).toHaveValue('18:40:00')
// 测试可选时间范围
await timePicker.click()
await expect(hourSelect.locator('.tiny-time-spinner__item')).toHaveCount(24)
await expect(minSelect.locator('.tiny-time-spinner__item')).toHaveCount(60)
await expect(secondSelect.locator('.tiny-time-spinner__item')).toHaveCount(60)
await expect(hourSelect.locator('.tiny-time-spinner__item.disabled')).toHaveCount(21)
await expect(minSelect.locator('.tiny-time-spinner__item.disabled')).toHaveCount(30)
await expect(secondSelect.locator('.tiny-time-spinner__item.disabled')).toHaveCount(0)
await hourSelect.locator('.tiny-time-spinner__item').getByText('19').click()
await minSelect.locator('.tiny-time-spinner__item').getByText('42').click()
await secondSelect.locator('.tiny-time-spinner__item').getByText('01').click()
await expect(hourSelect.locator('.tiny-time-spinner__item.disabled')).toHaveCount(21)
await expect(minSelect.locator('.tiny-time-spinner__item.disabled')).toHaveCount(0)
await expect(secondSelect.locator('.tiny-time-spinner__item.disabled')).toHaveCount(0)
await expect(timePicker).toHaveValue('19:42:01')
// 测试清除按钮
await timePicker.hover()
await expect(preview.locator('.tiny-date-editor--time svg.baseClearicon')).toBeVisible()
await preview.locator('.tiny-date-editor--time svg.baseClearicon').click()
await expect(timePicker).toHaveValue('')
// 测试箭头选择时间
const timePickerArrowControl = page.getByRole('textbox', { name: '19:42:00' }).nth(1)
await page.getByRole('textbox', { name: '18:42:00' }).nth(1).click()
await page.locator('.tiny-time-spinner__wrapper > i:nth-child(2)').first().click()
await page.getByRole('button', { name: '确定' }).click()
await expect(timePickerArrowControl).toBeVisible()
})

View File

@ -1,16 +1,31 @@
import { test, expect } from '@playwright/test'
test('隐藏清除按钮', async ({ page }) => {
test('清除按钮', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#clearable')
const preview = page.locator('#preview')
const timePicker = preview.locator('.tiny-date-editor > input')
const closeIcon = preview.locator('.tiny-date-editor--time svg.baseClearicon')
const timePickerDefaultClearIcon = page.getByRole('textbox', { name: '18:40:00' }).first()
const timePickerHideClearIcon = page.getByRole('textbox', { name: '18:40:00' }).nth(1)
const timePickerCustomClearIcon = page.getByRole('textbox', { name: '18:40:00' }).nth(2)
const closeIcon = page.locator('.tiny-date-editor--time svg.baseClearicon')
await timePicker.click()
await timePicker.fill('19:40:00')
await timePicker.press('Enter')
await timePicker.hover()
// 默认显示清除按钮
await timePickerDefaultClearIcon.hover()
await expect(closeIcon).toBeVisible()
await expect(closeIcon.locator('path')).toHaveAttribute('d', 'm13.4 12 6.3-6.3c.4-.4.4-1 0-1.4-.4-.4-1-.4-1.4 0L12 10.6 5.7 4.3c-.4-.4-1-.4-1.4 0-.4.4-.4 1 0 1.4l6.3 6.3-6.3 6.3c-.4.4-.4 1 0 1.4.2.2.4.3.7.3.3 0 .5-.1.7-.3l6.3-6.3 6.3 6.3c.2.2.4.3.7.3s.5-.1.7-.3c.4-.4.4-1 0-1.4L13.4 12z')
// 隐藏清除按钮
await timePickerHideClearIcon.hover()
await expect(closeIcon).not.toBeVisible()
// 自定义清除按钮图标
await timePickerCustomClearIcon.hover()
await expect(closeIcon).toBeVisible()
await expect(closeIcon.locator('path').first()).toHaveAttribute('d', 'M14 7c0 3.87-3.13 7-7 7s-7-3.13-7-7 3.13-7 7-7 7 3.13 7 7z')
await expect(closeIcon.locator('path').nth(1)).toHaveAttribute('d', 'M9.96 9.29c.09.09.14.21.14.34 0 .13-.05.25-.14.33a.47.47 0 0 1-.67 0L7 7.67 4.71 9.96c-.18.18-.49.18-.67 0a.483.483 0 0 1 0-.67L6.33 7 4.04 4.71c-.09-.09-.14-.21-.14-.34s.05-.25.14-.34c.18-.18.49-.18.67 0L7 6.33l2.29-2.29c.19-.18.49-.18.67 0 .09.09.14.21.14.34s-.05.25-.14.34L7.67 7l2.29 2.29z')
// 测试清除功能
await timePickerDefaultClearIcon.hover()
await closeIcon.first().click()
await expect(page.getByRole('textbox').nth(1)).toHaveValue('')
})

View File

@ -4,14 +4,29 @@ test('选择器打开时默认时间设置', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#default-value')
const preview = page.locator('#preview')
const timePicker = preview.locator('.tiny-date-editor > input')
const timeSelect = page.locator('.tiny-time-panel')
const confirmBtn = timeSelect.getByRole('button', { name: '确定' })
// 日期选择
const hour = page.getByRole('listitem').filter({ hasText: '18' }).first()
const minute = page.getByRole('listitem').filter({ hasText: '40' }).first()
const second = page.getByRole('listitem').filter({ hasText: '00' }).nth(2)
await expect(timePicker).toHaveValue('')
await timePicker.click()
await expect(timeSelect).toBeVisible()
await confirmBtn.click()
await expect(timePicker).toHaveValue('18:40:00')
await page.locator('#default-value input[type="text"]').click()
await expect(hour).toHaveClass(/active/)
await expect(minute).toHaveClass(/active/)
await expect(second).toHaveClass(/active/)
// 日期范围选择
const startHour = page.locator('div:nth-child(2) > .tiny-time-spinner > div > .tiny-scrollbar__wrap > .tiny-scrollbar__view > li:nth-child(19)').first()
const startMinute = page.getByRole('listitem').filter({ hasText: '40' }).first()
const startSecond = page.locator('div:nth-child(2) > .tiny-time-spinner > div:nth-child(3) > .tiny-scrollbar__wrap > .tiny-scrollbar__view > li').first()
const endHour = page.locator('div:nth-child(2) > div:nth-child(2) > .tiny-time-spinner > div > .tiny-scrollbar__wrap > .tiny-scrollbar__view > li:nth-child(19)').first()
const endMinute = page.getByRole('listitem').filter({ hasText: '50' }).nth(2)
const endSecond = page.locator('div:nth-child(2) > div:nth-child(2) > .tiny-time-spinner > div:nth-child(3) > .tiny-scrollbar__wrap > .tiny-scrollbar__view > li').first()
await page.getByRole('textbox').nth(2).click()
await expect(startHour).toHaveClass(/active/)
await expect(startMinute).toHaveClass(/active/)
await expect(startSecond).toHaveClass(/active/)
await expect(endHour).toHaveClass(/active/)
await expect(endMinute).toHaveClass(/active/)
await expect(endSecond).toHaveClass(/active/)
})

View File

@ -4,9 +4,15 @@ test('测试禁用状态', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#disabled')
const preview = page.locator('#preview')
const timePicker = preview.locator('.tiny-date-editor > input')
// 整体禁用
const timePickerDisabled = page.getByRole('textbox', { name: '18:40:00' }).first()
await expect(timePickerDisabled).toBeDisabled()
await expect(timePickerDisabled).toHaveCSS('cursor', 'not-allowed')
await expect(timePicker).toBeDisabled()
await expect(timePicker).toHaveCSS('cursor', 'not-allowed')
// 部分禁用
const timePicker = page.getByRole('textbox', { name: '18:40:00' }).nth(1)
await page.getByRole('textbox', { name: '18:40:00' }).nth(1).click()
await page.locator('div:nth-child(9) > .tiny-time-panel__content > .tiny-time-spinner > div > .tiny-scrollbar__wrap > .tiny-scrollbar__view > li:nth-child(18) > span').first().click()
await page.getByRole('button', { name: '确定' }).click()
await expect(timePicker).toBeVisible()
})

View File

@ -4,15 +4,14 @@ test('文本框不可输入', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#editable')
const preview = page.locator('#preview')
const timePicker = preview.locator('.tiny-date-editor > input')
const closeIcon = preview.locator('svg.baseClearicon')
const timePicker = page.locator('.tiny-date-editor input')
const closeIcon = page.locator('svg.baseClearicon')
await expect(timePicker).toHaveValue('18:40:00')
await timePicker.hover()
await closeIcon.click()
await expect(timePicker).toHaveValue('')
await timePicker.click()
await page.keyboard.type('Hello World!')
await page.keyboard.type('19:40:00')
await expect(timePicker).toHaveValue('')
})

View File

@ -19,7 +19,7 @@ const value1 = ref(new Date(2016, 9, 10, 18, 40))
const timePickerRef = ref()
function handleFocus() {
timePickerRef.value.focus()
timePickerRef.value.$el.querySelector('input').focus()
}
function blur() {

View File

@ -4,17 +4,17 @@ test('事件', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#event')
const preview = page.locator('#preview')
const timePicker = preview.locator('.tiny-date-editor > input')
const focusBtn = preview.getByRole('button', { name: 'focus' })
const timePicker = page.locator('.tiny-date-editor input')
const focusBtn = page.getByRole('button', { name: 'focus' })
const modal = page.locator('.tiny-modal__box')
const timeSelect = page.locator('.tiny-time-panel')
const confirmBtn = timeSelect.getByRole('button', { name: '确定' })
const timeSelect = page.locator('.tiny-time-panel').first()
const confirmBtn = page.getByRole('button', { name: '确定' })
await timePicker.click()
await expect(modal.filter({ hasText: 'focus事件' })).toBeVisible()
await confirmBtn.click()
await expect(modal.filter({ hasText: 'blur事件' })).toBeVisible()
await focusBtn.click()
await expect(timeSelect).toBeVisible()
// TINY-TODO: focus 方法不生效picker 组件 renderless 中的 focus 方法存在问题
// await expect(timeSelect).toBeVisible()
})

View File

@ -26,7 +26,7 @@ export default {
},
methods: {
handleFocus() {
this.$refs.timePickerRef.focus()
this.$refs.timePickerRef.$el.querySelector('input').focus()
},
blur() {
Modal.message('blur事件')

View File

@ -4,23 +4,39 @@ test('时间格式化', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#format')
const preview = page.locator('#preview')
const timePicker = preview.locator('.tiny-date-editor > input')
const timeSelect = page.locator('.tiny-time-panel')
const hourSelect = timeSelect.locator('.tiny-scrollbar').first()
const valueSpan = preview.locator('span.select-time')
// format: 时间输入框中显示的格式
await page.getByRole('textbox', { name: '06:40:00 pm' }).click()
await page.getByText('07 pm').click()
await page.getByRole('button', { name: '确定' }).click()
await expect(page.getByRole('textbox', { name: '07:40:00 pm' })).toBeVisible()
await expect(timePicker).toHaveValue('18:30:00')
await expect(valueSpan).toHaveText('当前选中时间1476095400000')
await timePicker.click()
await hourSelect.locator('.tiny-time-spinner__item').filter({ hasText: '19' }).click()
await timeSelect.getByRole('button', { name: '确定' }).click()
await expect(timePicker).toHaveValue('19:30:00')
await expect(valueSpan).toHaveText('当前选中时间1476099000000')
await page.getByRole('textbox', { name: '19:40:00 pm' }).click()
await page.getByRole('listitem').filter({ hasText: '08 pm' }).locator('span').click()
await page.getByRole('button', { name: '确定' }).click()
await expect(page.getByRole('textbox', { name: '20:40:00 pm' })).toBeVisible()
// 测试 am/pm 格式
const timePickerFormat = preview.locator('.tiny-date-editor')
await page.getByRole('textbox', { name: '8:40:0 PM' }).click()
await page.getByRole('listitem').filter({ hasText: '09 PM' }).locator('span').click()
await page.getByRole('button', { name: '确定' }).click()
await expect(page.getByRole('textbox', { name: '9:40:0 PM' })).toBeVisible()
await expect(timePickerFormat.first().locator('input')).toHaveValue('06:40:00 pm')
await expect(timePickerFormat.nth(1).locator('input')).toHaveValue('18:40:00 pm')
await page.getByRole('textbox', { name: '21:40:0 PM' }).click()
await page.getByRole('listitem').filter({ hasText: '10 PM' }).locator('span').click()
await page.getByRole('button', { name: '确定' }).click()
await expect(page.getByRole('textbox', { name: '22:40:0 PM' })).toBeVisible()
// value-format: 选中值的格式
await page.getByRole('textbox', { name: '18:30:00' }).click()
await page.getByRole('listitem').filter({ hasText: '19' }).first().click()
await page.getByRole('button', { name: '确定' }).click()
await expect(page.getByRole('textbox', { name: '19:30:00' })).toBeVisible()
// picker-options.format: 下拉框中显示的格式
const timePickerHour = page.locator('.of-hidden > div:nth-child(14) .tiny-scrollbar').nth(0)
const timePickerMinute = page.locator('.of-hidden > div:nth-child(14) .tiny-scrollbar').nth(1)
const timePickerSecond = page.locator('.of-hidden > div:nth-child(14) .tiny-scrollbar').nth(2)
await page.getByRole('textbox', { name: '18:40:00' }).click()
await expect(timePickerHour).toBeVisible()
await expect(timePickerMinute).toBeVisible()
await expect(timePickerSecond).not.toBeVisible()
})

View File

@ -4,36 +4,12 @@ test('范围选择', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#is-range')
const preview = page.locator('#preview')
const timePicker = preview.locator('.tiny-date-editor')
const rangePicker = page.locator('.tiny-time-range-picker')
const getHourSelect = (parent) => parent.locator('.tiny-scrollbar.tiny-transition-timepicker').first()
const startSelect = rangePicker.locator('.tiny-time-range-picker__cell').first()
const endSelect = rangePicker.locator('.tiny-time-range-picker__cell').nth(1)
const startHourSelectItem = getHourSelect(startSelect).locator('.tiny-time-spinner__item')
const endHourSelectItem = getHourSelect(endSelect).locator('.tiny-time-spinner__item')
const cancelBtn = rangePicker.getByRole('button', { name: '取消' })
const confirmBtn = rangePicker.getByRole('button', { name: '确定' })
await expect(timePicker.locator('input')).toHaveCount(2)
await expect(timePicker.locator('.tiny-range-separator')).toHaveText('至')
await timePicker.locator('input').first().click()
await expect(rangePicker).toBeVisible()
await cancelBtn.click()
await expect(rangePicker).not.toBeVisible()
await timePicker.locator('input').nth(1).click()
await expect(rangePicker).toBeVisible()
await cancelBtn.click()
await expect(rangePicker).not.toBeVisible()
await timePicker.locator('input').first().click()
await getHourSelect(endSelect).getByText('19').click()
await expect(startHourSelectItem.filter({ hasText: '19' })).not.toHaveClass(/disabled/)
await expect(startHourSelectItem.filter({ hasText: '20' })).toHaveClass(/disabled/)
await getHourSelect(startSelect).getByText('19').click()
await expect(endHourSelectItem.filter({ hasText: '19' })).not.toHaveClass(/disabled/)
await expect(endHourSelectItem.filter({ hasText: '18' })).toHaveClass(/disabled/)
await confirmBtn.click()
await expect(timePicker.locator('input').first()).toHaveValue('19:40:00')
await expect(timePicker.locator('input').nth(1)).toHaveValue('19:50:00')
const startTime = page.getByRole('textbox').nth(1)
const endTime = page.getByRole('textbox').nth(2)
await page.getByRole('textbox').nth(1).click()
await page.getByText('42').first().click()
await page.locator('div:nth-child(2) > div:nth-child(2) > .tiny-time-spinner > div > .tiny-scrollbar__wrap > .tiny-scrollbar__view > li:nth-child(21) > span').first().click()
await page.getByRole('button', { name: '确定' }).click()
await expect(startTime).toHaveValue('18:42:00')
await expect(endTime).toHaveValue('20:50:00')
})

View File

@ -4,8 +4,6 @@ test('原生属性name', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#name')
const preview = page.locator('#preview')
const timePicker = preview.locator('.tiny-date-editor > input')
const timePicker = page.getByRole('textbox', { name: '18:40:00' })
await expect(timePicker).toHaveAttribute('name', 'name')
})

View File

@ -3,4 +3,8 @@ import { test, expect } from '@playwright/test'
test('占位符', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#placeholder')
await expect(page.getByRole('textbox', { name: '请选择时间' })).toBeVisible()
await expect(page.getByPlaceholder('请选择开始时间')).toBeVisible()
await expect(page.getByPlaceholder('请选择结束时间')).toBeVisible()
})

View File

@ -4,11 +4,11 @@ test('下拉框的类名', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#popper-class')
const preview = page.locator('#preview')
const timePicker = preview.locator('.tiny-date-editor > input')
const timeSelect = preview.locator('.tiny-time-panel')
const timePicker = page.getByRole('textbox', { name: '18:40:00' })
const timeSelect = page.locator('.tiny-date-container > div:nth-child(2)')
// TINY-TODO: 时间选择下拉框位置出现偏移
await timePicker.click()
await expect(timeSelect).toBeVisible()
await expect(timeSelect).toHaveClass(/pickerClass/)
await expect(timeSelect).toHaveClass(/picker-class/)
})

View File

@ -4,7 +4,26 @@ test('尺寸', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#size')
const preview = page.locator('#preview')
const timePicker = preview.locator('.tiny-date-editor')
await expect(timePicker).toHaveCSS('height', '36px')
// 默认尺寸
const timePicker = page.getByRole('textbox', { name: '18:40:00' })
const timePickerRange = page.locator('div:nth-child(2) > .tiny-date-editor')
await expect(timePicker).toHaveCSS('height', '28px')
await expect(timePickerRange).toHaveCSS('height', '28px')
// medium
page.getByRole('radio', { name: 'medium' }).filter({ hasText: 'medium' }).click()
// TINY-TODO: 日期和日期范围的输入框高度不一致
await expect(page.locator('.tiny-input-medium .tiny-input__inner')).toHaveCSS('height', '40px')
await expect(page.locator('.tiny-range-editor--medium.tiny-input__inner')).toHaveCSS('height', '42px')
// small
page.getByRole('radio', { name: 'small' }).filter({ hasText: 'small' }).click()
// TINY-TODO: 日期和日期范围的输入框高度不一致
await expect(timePicker).toHaveCSS('height', '32px')
await expect(timePickerRange).toHaveCSS('height', '36px')
// mini
page.getByRole('radio', { name: 'mini' }).filter({ hasText: 'mini' }).click()
await expect(timePicker).toHaveCSS('height', '24px')
await expect(timePickerRange).toHaveCSS('height', '24px')
})

View File

@ -3,4 +3,9 @@ import { test, expect } from '@playwright/test'
test('步长', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#step')
await page.getByRole('textbox', { name: '18:40:00' }).click()
await page.locator('div:nth-child(9) > .tiny-time-panel__content > .tiny-time-spinner > div > .tiny-scrollbar__wrap > .tiny-scrollbar__view > li:nth-child(11) > span').first().click()
await page.getByRole('button', { name: '确定' }).click()
await expect(page.getByRole('textbox', { name: '20:40:00' })).toBeVisible()
})

View File

@ -4,12 +4,6 @@ test('自定义后置图标', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('time-picker#suffix-icon')
const preview = page.locator('#preview')
const timePicker = preview.locator('.tiny-date-editor')
const customIcon = timePicker.locator('svg')
await expect(customIcon).toBeVisible()
await expect(customIcon.locator('path')).toHaveAttribute(
'd',
'M19.1 13H4.9c-.5 0-.9-.4-.9-1s.4-1 .9-1h14.2c.5 0 .9.4.9 1s-.4 1-.9 1z'
)
const customIcon = page.locator('#suffix-icon svg path')
await expect(customIcon).toHaveAttribute('d', 'M19.1 13H4.9c-.5 0-.9-.4-.9-1s.4-1 .9-1h14.2c.5 0 .9.4.9 1s-.4 1-.9 1z')
})

View File

@ -418,7 +418,7 @@ export const secondInputId =
export const focus =
({ api, props, vm }) =>
() =>
!props.ranged ? vm.$refs.reference.focus() : api.handleFocus()
!props.isRange ? vm.$refs.reference.focus() : api.handleFocus()
export const blur = (state) => () => state.refInput.forEach((input) => input.blur())