diff --git a/examples/sites/demos/pc/app/select/allow-create.spec.ts b/examples/sites/demos/pc/app/select/allow-create.spec.ts index ff017cb4a..038d3bf64 100644 --- a/examples/sites/demos/pc/app/select/allow-create.spec.ts +++ b/examples/sites/demos/pc/app/select/allow-create.spec.ts @@ -1,34 +1,48 @@ import { test, expect } from '@playwright/test' -test('click', async ({ page }) => { +test('点击选中', async ({ page }) => { + page.on('pageerror', (exception) => expect(exception).toBeNull()) + await page.waitForTimeout(300) await page.goto('select#allow-create') - const input = page.locator('#preview .tiny-input__inner') + + const wrap = page.locator('#allow-create') + const dropdown = page.locator('.tiny-select-dropdown') + const input = wrap.locator('.tiny-input__inner').first() + await input.click() await input.fill('测试allow-create') const KeyboardEvent = await page.evaluateHandle(() => new KeyboardEvent('keyup')) await input.dispatchEvent('keyup', { KeyboardEvent }) + await expect(input).toHaveValue('测试allow-create') - await page.getByRole('listitem').filter({ hasText: '测试allow-create' }).click() + await dropdown.getByRole('listitem').filter({ hasText: '测试allow-create' }).click() await expect(input).toHaveValue('测试allow-create') + await input.click() await expect(input).toHaveValue('') - await expect(page.getByRole('listitem').filter({ hasText: '测试allow-create' })).toHaveClass(/selected/) + await expect(dropdown.getByRole('listitem').filter({ hasText: '测试allow-create' })).toHaveClass(/selected/) }) -test('press-enter', async ({ page }) => { +test('enter 选中', async ({ page }) => { + page.on('pageerror', (exception) => expect(exception).toBeNull()) + await page.waitForTimeout(300) await page.goto('select#allow-create') - const input = page.locator('#preview .tiny-input__inner') - await input.click() + const wrap = page.locator('#allow-create') + const dropdown = page.locator('.tiny-select-dropdown').nth(1) + const input = wrap.locator('.tiny-input__inner').nth(1) + + await input.click() await input.press('a') await input.press('b') + await page.waitForTimeout(300) await input.press('Enter') - await expect(page.locator('.tiny-select-dropdown__wrap')).toBeHidden() + await expect(dropdown).toBeHidden() await expect(input).toHaveValue('ab') await input.click() await expect(input).toHaveValue('') - await expect(page.getByRole('listitem').filter({ hasText: 'ab' })).toHaveClass(/selected/) + await expect(dropdown.getByRole('listitem').filter({ hasText: 'ab' })).toHaveClass(/selected/) }) diff --git a/examples/sites/demos/pc/app/select/automatic-dropdown-composition-api.vue b/examples/sites/demos/pc/app/select/automatic-dropdown-composition-api.vue index df94a46af..764b59b08 100644 --- a/examples/sites/demos/pc/app/select/automatic-dropdown-composition-api.vue +++ b/examples/sites/demos/pc/app/select/automatic-dropdown-composition-api.vue @@ -46,6 +46,6 @@ p { line-height: 1.5; } .tiny-button { - margin-bottom: 10px; + margin-right: 10px; } diff --git a/examples/sites/demos/pc/app/select/automatic-dropdown.spec.ts b/examples/sites/demos/pc/app/select/automatic-dropdown.spec.ts index 0db1074f7..825a69c32 100644 --- a/examples/sites/demos/pc/app/select/automatic-dropdown.spec.ts +++ b/examples/sites/demos/pc/app/select/automatic-dropdown.spec.ts @@ -1,14 +1,29 @@ import { test, expect } from '@playwright/test' -test('automatic-dropdown', async ({ page }) => { +test('不可搜索时,获取焦点不下拉', async ({ page }) => { await page.goto('select#automatic-dropdown') - const input = page.locator('#preview .tiny-input__inner') + const wrap = page.locator('#automatic-dropdown') + const input = wrap.locator('.tiny-input__inner').first() + const dropdown = page.locator('.tiny-select-dropdown').first() - await page.getByRole('button', { name: '点击获取焦点' }).click() - await page.getByRole('listitem').filter({ hasText: '双皮奶' }).click() + await wrap.getByRole('button').first().click() + // 聚焦高亮 + await expect(input).toHaveCSS('border-color', 'rgb(94, 124, 224)') + // 不下拉 + await expect(dropdown).toBeHidden() +}) + +test('可搜索时,获取焦点自动下拉', async ({ page }) => { + await page.goto('select#automatic-dropdown') + const wrap = page.locator('#automatic-dropdown') + const input = wrap.locator('.tiny-input__inner').nth(1) + const dropdown = page.locator('.tiny-select-dropdown').nth(1) + + await wrap.getByRole('button').nth(1).click() + // 聚焦下拉 + await dropdown.getByRole('listitem').filter({ hasText: '双皮奶' }).click() await expect(input).toHaveValue('双皮奶') + // 验证选中 await input.click() await expect(page.getByRole('listitem').filter({ hasText: '双皮奶' })).toHaveClass(/selected/) - await page.locator('.rel').click() - await expect(page.locator('div').filter({ hasText: '黄金糕双皮奶蚵仔煎龙须面北京烤鸭' }).first()).toBeHidden() }) diff --git a/examples/sites/demos/pc/app/select/automatic-dropdown.vue b/examples/sites/demos/pc/app/select/automatic-dropdown.vue index 6e57c14e9..62753b1b2 100644 --- a/examples/sites/demos/pc/app/select/automatic-dropdown.vue +++ b/examples/sites/demos/pc/app/select/automatic-dropdown.vue @@ -54,6 +54,6 @@ p { line-height: 1.5; } .tiny-button { - margin-bottom: 10px; + margin-right: 10px; } diff --git a/examples/sites/demos/pc/app/select/basic-usage.spec.ts b/examples/sites/demos/pc/app/select/basic-usage.spec.ts index 1d73a4689..5ef100fce 100644 --- a/examples/sites/demos/pc/app/select/basic-usage.spec.ts +++ b/examples/sites/demos/pc/app/select/basic-usage.spec.ts @@ -1,18 +1,20 @@ import { test, expect } from '@playwright/test' -test('basic', async ({ page }) => { +test('基础用法', async ({ page }) => { await page.goto('select#basic-usage') - const input = page.locator('#preview .tiny-input__inner') + const wrap = page.locator('#basic-usage') + const input = wrap.locator('.tiny-input__inner') + const dropdown = page.locator('.tiny-select-dropdown') await input.click() - await page.getByRole('listitem').filter({ hasText: '蚵仔煎' }).click() + await dropdown.getByRole('listitem').filter({ hasText: '蚵仔煎' }).click() await expect(input).toHaveValue('蚵仔煎') - await page.locator('#preview svg').nth(1).click() + await wrap.locator('.tiny-input__suffix svg').click() await expect(page.getByRole('listitem').filter({ hasText: '蚵仔煎' })).toHaveClass(/selected/) - await page.getByRole('listitem').filter({ hasText: '北京烤鸭' }).click() + await dropdown.getByRole('listitem').filter({ hasText: '北京烤鸭' }).click() await expect(input).toHaveValue('北京烤鸭') await input.click() - await expect(page.getByRole('listitem').filter({ hasText: '北京烤鸭' })).toHaveClass(/selected/) - await page.locator('.rel').click() + await expect(dropdown.getByRole('listitem').filter({ hasText: '北京烤鸭' })).toHaveClass(/selected/) + await wrap.click() await expect(page.locator('div').filter({ hasText: '黄金糕双皮奶蚵仔煎龙须面北京烤鸭' }).first()).toBeHidden() }) diff --git a/examples/sites/demos/pc/app/select/binding-obj.spec.ts b/examples/sites/demos/pc/app/select/binding-obj.spec.ts index a1c918d35..c5a4310c0 100644 --- a/examples/sites/demos/pc/app/select/binding-obj.spec.ts +++ b/examples/sites/demos/pc/app/select/binding-obj.spec.ts @@ -2,15 +2,19 @@ import { test, expect } from '@playwright/test' test('binding-obj', async ({ page }) => { await page.goto('select#binding-obj') - const input = page.locator('#preview .tiny-input__inner') - const valueLocator = page.locator('#preview .value') + + const wrap = page.locator('#binding-obj') + const input = wrap.locator('.tiny-input__inner') + const dropdown = page.locator('.tiny-select-dropdown') + const valueLocator = wrap.locator('.value') await input.click() - await page.getByRole('listitem').filter({ hasText: '龙须面' }).click() + await dropdown.getByRole('listitem').filter({ hasText: '龙须面' }).click() await expect(input).toHaveValue('龙须面') await expect(valueLocator).toHaveText('{ "val": "选项4", "id": 4 }') + await input.click() - await page.getByRole('listitem').filter({ hasText: '蚵仔煎' }).click() + await dropdown.getByRole('listitem').filter({ hasText: '蚵仔煎' }).click() await expect(input).toHaveValue('蚵仔煎') await expect(valueLocator).toHaveText('{ "val": "选项3", "id": 3 }') }) diff --git a/examples/sites/demos/pc/app/select/cache-usage.spec.ts b/examples/sites/demos/pc/app/select/cache-usage.spec.ts index 08ddfbd08..3a3aeac15 100644 --- a/examples/sites/demos/pc/app/select/cache-usage.spec.ts +++ b/examples/sites/demos/pc/app/select/cache-usage.spec.ts @@ -2,13 +2,17 @@ import { expect, test } from '@playwright/test' test('cache-op', async ({ page }) => { await page.goto('select#cache-usage') - const input = page.locator('#preview .tiny-input__inner') - const cacheValue = page.locator('#preview .cache-value') + + const wrap = page.locator('#cache-usage') + const dropdown = page.locator('.tiny-select-dropdown') + const input = wrap.locator('.tiny-input__inner') + const cacheValue = wrap.locator('.cache-value') await input.click() - await page.getByRole('listitem').filter({ hasText: '黄金糕' }).click() + await dropdown.getByRole('listitem').filter({ hasText: '黄金糕' }).click() await expect(cacheValue).toContainText(['选项1']) + await input.click() - await page.getByRole('listitem').filter({ hasText: '双皮奶' }).click() + await dropdown.getByRole('listitem').filter({ hasText: '双皮奶' }).click() await expect(cacheValue).toContainText(['选项2']) }) diff --git a/examples/sites/demos/pc/app/select/clearable.spec.ts b/examples/sites/demos/pc/app/select/clearable.spec.ts index 0b417f5dc..2d3503189 100644 --- a/examples/sites/demos/pc/app/select/clearable.spec.ts +++ b/examples/sites/demos/pc/app/select/clearable.spec.ts @@ -2,14 +2,19 @@ import { test, expect } from '@playwright/test' test('clearable', async ({ page }) => { await page.goto('select#clearable') - const input = page.locator('#preview .tiny-input__inner') - const icon = page.locator('#preview .tiny-input__suffix') + const wrap = page.locator('#clearable') + const dropdown = page.locator('.tiny-select-dropdown') + const input = wrap.locator('.tiny-input__inner') + const icon = wrap.locator('.tiny-input__suffix') + // 验证默认值 await expect(input).toHaveValue('蚵仔煎') + // 验证清空 await input.hover() await icon.click() await expect(input).toHaveValue('') + // 验证选中 await icon.click() - await page.getByRole('listitem').filter({ hasText: '双皮奶' }).click() + await dropdown.getByRole('listitem').filter({ hasText: '双皮奶' }).click() await expect(input).toHaveValue('双皮奶') }) diff --git a/examples/sites/demos/pc/app/select/collapse-tags.spec.ts b/examples/sites/demos/pc/app/select/collapse-tags.spec.ts index d384aa4a1..9339e5791 100644 --- a/examples/sites/demos/pc/app/select/collapse-tags.spec.ts +++ b/examples/sites/demos/pc/app/select/collapse-tags.spec.ts @@ -2,17 +2,29 @@ import { test, expect } from '@playwright/test' test('collapse-tags', async ({ page }) => { await page.goto('select#collapse-tags') - await expect(page.locator('span.tiny-tag')).toHaveCount(2) - await expect(page.locator('span').filter({ hasText: '黄金糕' }).nth(1)).toBeVisible() - await expect(page.locator('span').filter({ hasText: '+ 1' }).nth(1)).toBeVisible() - await page.getByText('黄金糕+ 1').click() - await expect(page.getByRole('listitem').filter({ hasText: '黄金糕' })).toHaveClass(/selected/) - await expect(page.getByRole('listitem').filter({ hasText: '双皮奶' })).toHaveClass(/selected/) - await page.getByRole('listitem').filter({ hasText: '黄金糕' }).locator('span').nth(2).click() - await expect(page.locator('span').filter({ hasText: '+ 1' }).nth(1)).toBeHidden() - await expect(page.locator('span.tiny-tag')).toHaveCount(1) - await page.getByRole('listitem').filter({ hasText: '蚵仔煎' }).locator('span').nth(2).click() - await page.getByRole('listitem').filter({ hasText: '北京烤鸭' }).locator('span').nth(2).click() - await expect(page.locator('span').filter({ hasText: '+ 2' }).nth(1)).toBeVisible() - await expect(page.locator('span.tiny-tag')).toHaveCount(2) + const wrap = page.locator('#collapse-tags') + const dropdown = page.locator('.tiny-select-dropdown') + const tag = wrap.locator('.tiny-tag') + const option = dropdown.locator('.tiny-option') + + // 验证默认值的折叠标签显示 + await expect(tag).toHaveCount(2) + await expect(tag.filter({ hasText: '黄金糕' })).toBeVisible() + await expect(tag.filter({ hasText: '+ 1' })).toBeVisible() + + // 点击下拉后选中效果 + await tag.first().click() + await expect(option.filter({ hasText: '黄金糕' })).toHaveClass(/selected/) + await expect(option.filter({ hasText: '双皮奶' })).toHaveClass(/selected/) + + // 取消选中一个 + await option.filter({ hasText: '黄金糕' }).locator('span').nth(2).click() + await expect(tag.filter({ hasText: '+ 1' })).toBeHidden() + await expect(tag).toHaveCount(1) + + // 再选中2个 + await option.filter({ hasText: '蚵仔煎' }).locator('span').nth(2).click() + await option.filter({ hasText: '北京烤鸭' }).locator('span').nth(2).click() + await expect(tag.filter({ hasText: '+ 2' })).toBeVisible() + await expect(tag).toHaveCount(2) }) diff --git a/examples/sites/demos/pc/app/select/tag-select-composition-api.vue b/examples/sites/demos/pc/app/select/copy-multi-composition-api.vue similarity index 100% rename from examples/sites/demos/pc/app/select/tag-select-composition-api.vue rename to examples/sites/demos/pc/app/select/copy-multi-composition-api.vue diff --git a/examples/sites/demos/pc/app/select/copy-multi.spec.ts b/examples/sites/demos/pc/app/select/copy-multi.spec.ts new file mode 100644 index 000000000..d81dd5c29 --- /dev/null +++ b/examples/sites/demos/pc/app/select/copy-multi.spec.ts @@ -0,0 +1,49 @@ +import { test, expect } from '@playwright/test' + +test('多选复制单个标签', async ({ page }) => { + await page.goto('select#copy-multi') + + await page.waitForTimeout(1000) + await page.mouse.move(392, 316) + await page.waitForTimeout(1000) + await page.mouse.down() + await page.waitForTimeout(1000) + await page.mouse.move(346, 316) + await page.waitForTimeout(1000) + await page.mouse.up() + await page.keyboard.press('Control+C') + const valueInput = page.locator('.copy-value .tiny-input__inner') + await expect(valueInput).toHaveValue('') + await valueInput.focus() + await page.keyboard.press('Control+V') + await page.waitForTimeout(200) + await expect(valueInput).toHaveValue('黄金糕') +}) + +test('多选一键复制所有标签', async ({ page }) => { + await page.goto('select#copy-multi') + + const wrap = page.locator('#copy-multi') + const select = wrap.locator('.tiny-select').nth(1) + const copyValueInput = wrap.locator('.copy-value .tiny-input__inner') + + await select.hover() + await select.locator('.tiny-select__copy > .tiny-svg > .st0').click() + + await copyValueInput.press('Control+V') + await expect(copyValueInput).toHaveValue('黄金糕,双皮奶') +}) + +test('多选设置复制文本分隔符', async ({ page }) => { + await page.goto('select#copy-multi') + + const wrap = page.locator('#copy-multi') + const select = wrap.locator('.tiny-select').nth(2) + const copyValueInput = wrap.locator('.copy-value .tiny-input__inner') + + await select.hover() + await select.locator('.tiny-select__copy > .tiny-svg > .st0').click() + + await copyValueInput.press('Control+V') + await expect(copyValueInput).toHaveValue('黄金糕/双皮奶') +}) diff --git a/examples/sites/demos/pc/app/select/tag-select.vue b/examples/sites/demos/pc/app/select/copy-multi.vue similarity index 100% rename from examples/sites/demos/pc/app/select/tag-select.vue rename to examples/sites/demos/pc/app/select/copy-multi.vue diff --git a/examples/sites/demos/pc/app/select/search-allow-copy-composition-api.vue b/examples/sites/demos/pc/app/select/copy-single-composition-api.vue similarity index 100% rename from examples/sites/demos/pc/app/select/search-allow-copy-composition-api.vue rename to examples/sites/demos/pc/app/select/copy-single-composition-api.vue diff --git a/examples/sites/demos/pc/app/select/copy-single.spec.ts b/examples/sites/demos/pc/app/select/copy-single.spec.ts new file mode 100644 index 000000000..0d07afdbd --- /dev/null +++ b/examples/sites/demos/pc/app/select/copy-single.spec.ts @@ -0,0 +1,70 @@ +import { test, expect } from '@playwright/test' + +test('单选无需配置可复制', async ({ page }) => { + await page.goto('select#copy-single') + + const wrap = page.locator('#copy-single') + const valueInput = wrap.locator('.custom .tiny-input__inner') + + await page.waitForTimeout(1000) + await page.mouse.move(393, 285) + await page.waitForTimeout(1000) + await page.mouse.down() + await page.waitForTimeout(1000) + await page.mouse.move(345, 285) + await page.waitForTimeout(200) + await page.mouse.up() + await page.keyboard.press('Control+C') + await expect(valueInput).toHaveValue('') + await valueInput.focus() + await page.keyboard.press('Control+V') + await page.waitForTimeout(200) + await expect(valueInput).toHaveValue('黄金糕') +}) + +test('单选可搜索配置 allow-copy 可复制', async ({ page }) => { + await page.goto('select#copy-single') + + const wrap = page.locator('#copy-single') + const select = wrap.locator('.tiny-select').nth(1) + const valueInput = wrap.locator('.custom .tiny-input__inner') + + await page.waitForTimeout(800) + await page.mouse.move(400, 350) + await page.waitForTimeout(800) + await page.mouse.down() + await page.waitForTimeout(800) + await page.mouse.move(344, 350) + await page.waitForTimeout(200) + await page.mouse.up() + await page.waitForTimeout(800) + + await page.keyboard.press('Control+C') + await expect(valueInput).toHaveValue('') + await valueInput.click() + await page.keyboard.press('Control+V') + await page.waitForTimeout(2000) + await expect(valueInput).toHaveValue('黄金糕') +}) + +test('单选远程搜索配置 allow-copy 可复制', async ({ page }) => { + await page.goto('select#copy-single') + + const wrap = page.locator('#copy-single') + const valueInput = wrap.locator('.custom .tiny-input__inner') + + await page.waitForTimeout(1000) + await page.mouse.move(410, 433) + await page.waitForTimeout(1000) + await page.mouse.down() + await page.waitForTimeout(1000) + await page.mouse.move(346, 433) + await page.waitForTimeout(200) + await page.mouse.up() + await page.keyboard.press('Control+C') + await expect(valueInput).toHaveValue('') + await valueInput.focus() + await page.keyboard.press('Control+V') + await page.waitForTimeout(200) + await expect(valueInput).toHaveValue('Alabama') +}) diff --git a/examples/sites/demos/pc/app/select/search-allow-copy.vue b/examples/sites/demos/pc/app/select/copy-single.vue similarity index 97% rename from examples/sites/demos/pc/app/select/search-allow-copy.vue rename to examples/sites/demos/pc/app/select/copy-single.vue index c3d23abca..59dfc6066 100644 --- a/examples/sites/demos/pc/app/select/search-allow-copy.vue +++ b/examples/sites/demos/pc/app/select/copy-single.vue @@ -20,7 +20,7 @@

粘贴至此处:

- + diff --git a/examples/sites/demos/pc/app/select/disabled.spec.ts b/examples/sites/demos/pc/app/select/disabled.spec.ts index 184303988..77f9c079e 100644 --- a/examples/sites/demos/pc/app/select/disabled.spec.ts +++ b/examples/sites/demos/pc/app/select/disabled.spec.ts @@ -1,41 +1,84 @@ import { test, expect } from '@playwright/test' -test('disabled', async ({ page }) => { +test('下拉禁用', async ({ page }) => { await page.goto('select#disabled') - const input = page.locator('#preview .tiny-input__inner') + const wrap = page.locator('#disabled') + const input = wrap.locator('.tiny-input__inner').first() + const hasDisabled = await input.evaluate((input) => input.hasAttribute('disabled')) await expect(hasDisabled).toBe(true) }) -test('disabled-options-multiple', async ({ page }) => { - await page.goto('http://localhost:7130/pc/select/disabled-options') - const select = page.locator('#preview .tiny-select') - const tags = page.locator('#preview .tiny-select .tiny-tag') +test('多选某项禁用', async ({ page }) => { + await page.goto('select#disabled') + const wrap = page.locator('#disabled') + const select = wrap.locator('.tiny-select').nth(1) + const dropdown = page.locator('body > .tiny-select-dropdown') + const tag = select.locator('.tiny-tag') + const option = dropdown.locator('.tiny-option') + + await expect(tag).toHaveCount(0) + await select.click() + await expect(option.filter({ hasText: '双皮奶' })).toHaveClass(/is-disabled/) + + await option.filter({ hasText: '双皮奶' }).click() + await expect(tag).toHaveCount(0) + + await option.filter({ hasText: '黄金糕' }).click() + await expect(tag).toHaveCount(1) + await expect(tag.filter({ hasText: '黄金糕' })).toHaveCount(1) +}) + +test('单选某项禁用', async ({ page }) => { + await page.goto('select#disabled') + const wrap = page.locator('#disabled') + const select = wrap.locator('.tiny-select').nth(2) + const input = select.locator('.tiny-input__inner') + const dropdown = page.locator('body > .tiny-select-dropdown') + const option = dropdown.locator('.tiny-option') await select.click() - await expect(page.getByRole('listitem').filter({ hasText: '黄金糕' })).toHaveClass(/is-disabled/) - await expect(page.getByRole('listitem').filter({ hasText: '蚵仔煎' })).toHaveClass(/is-disabled/) - await page.getByRole('listitem').filter({ hasText: '黄金糕' }).click() - await expect(tags).toHaveCount(0) - await page.getByRole('listitem').filter({ hasText: '双皮奶' }).click() - await expect(tags).toHaveCount(1) - await expect(tags.filter({ hasText: '双皮奶' })).toHaveCount(1) + await expect(option.filter({ hasText: '全部' })).toHaveCount(0) + await expect(option.filter({ hasText: '双皮奶' })).toHaveClass(/is-disabled/) + + await option.filter({ hasText: '双皮奶' }).click() + await expect(dropdown).toBeVisible() + await expect(input).toHaveValue('') + + await option.filter({ hasText: '黄金糕' }).click() + await expect(dropdown).toBeHidden() + await expect(input).toHaveValue('黄金糕') }) -test('disabled-and-selected-options', async ({ page }) => { - await page.goto('http://localhost:7130/pc/select/disabled-and-selected-options') - const slect = page.locator('#preview .tiny-select') - const tags = page.locator('#preview .tiny-select .tiny-tag') - const listitem = page.getByRole('listitem') - await expect(tags.filter({ hasText: '黄金糕' }).locator('svg')).toHaveCount(0) - await slect.click() - await expect(listitem.filter({ hasText: '全部' })).toHaveCount(0) - await expect(listitem.filter({ hasText: '黄金糕' })).toHaveClass(/is-disabled/) - await page.getByRole('listitem').filter({ hasText: '双皮奶' }).click() - await expect(tags.filter({ hasText: '黄金糕' }).locator('.tiny-svg')).toHaveCount(0) - await expect(tags.filter({ hasText: '双皮奶' }).locator('.tiny-svg')).toHaveCount(1) - await page.getByRole('listitem').filter({ hasText: '黄金糕' }).click() - await expect(tags.filter({ hasText: '黄金糕' }).locator('.tiny-svg')).toHaveCount(0) +test('多选,禁用项默认选中', async ({ page }) => { + await page.goto('select#disabled') + const wrap = page.locator('#disabled') + const select = wrap.locator('.tiny-select').nth(3) + const dropdown = page.locator('body > .tiny-select-dropdown') + const tag = select.locator('.tiny-tag') + const option = dropdown.locator('.tiny-option') + + // 默认值显示tag数 + await expect(tag).toHaveCount(2) + // 禁用项默认选中不显示关闭图标 + await expect(tag.filter({ hasText: '双皮奶' }).locator('svg')).toHaveCount(0) + // 非禁用项显示关闭图标 + await expect(tag.filter({ hasText: '蚵仔煎' }).locator('svg')).toHaveCount(1) + + // 下拉禁用和默认选中的效果 + await select.click() + await expect(option.filter({ hasText: '全部' })).toHaveCount(1) + await expect(option.filter({ hasText: '双皮奶' })).toHaveClass(/is-disabled/) + await expect(option.filter({ hasText: '双皮奶' })).toHaveClass(/selected/) + await expect(option.filter({ hasText: '蚵仔煎' })).toHaveClass(/selected/) + + // 点击禁用项不取消选中 + await option.filter({ hasText: '双皮奶' }).click() + await expect(dropdown).toBeVisible() + await expect(tag).toHaveCount(2) + + // 选中其他项 + await option.filter({ hasText: '黄金糕' }).click() + await expect(dropdown).toBeVisible() + await expect(tag).toHaveCount(3) }) - - diff --git a/examples/sites/demos/pc/app/select/events-composition-api.vue b/examples/sites/demos/pc/app/select/events-composition-api.vue index 7d329b390..271a045ef 100644 --- a/examples/sites/demos/pc/app/select/events-composition-api.vue +++ b/examples/sites/demos/pc/app/select/events-composition-api.vue @@ -45,37 +45,38 @@ const value2 = ref([]) const change = () => { Modal.message({ - message: 'change 事件' + message: 'change 事件', + duration: 500 }) } const clear = () => { Modal.message({ - message: 'clear 事件' + message: '触发 clear 事件' }) } const focus = () => { Modal.message({ - message: 'focus 事件' + message: '触发 focus 事件' }) } const blur = () => { Modal.message({ - message: 'blur 事件' + message: '触发 blur 事件' }) } const removeTag = () => { Modal.message({ - message: 'remove-tag 事件' + message: '触发 remove-tag 事件' }) } const visibleChange = () => { Modal.message({ - message: 'visible-change 事件' + message: '触发 visible-change 事件' }) } diff --git a/examples/sites/demos/pc/app/select/events.spec.ts b/examples/sites/demos/pc/app/select/events.spec.ts index cd332ed57..194e3c768 100644 --- a/examples/sites/demos/pc/app/select/events.spec.ts +++ b/examples/sites/demos/pc/app/select/events.spec.ts @@ -1,76 +1,71 @@ import { test, expect } from '@playwright/test' -test('focus', async ({ page }) => { - await page.goto('select#envts-change') +test('单选事件', async ({ page }) => { + await page.goto('select#events') + const wrap = page.locator('#events') + const select = wrap.locator('.tiny-select').first() + const input = select.locator('.tiny-input__inner') + const dropdown = page.locator('body > .tiny-select-dropdown') + const option = dropdown.locator('.tiny-option') const model = page.locator('.tiny-modal') - const input = page.locator('#preview .tiny-input__inner') await input.click() await page.waitForTimeout(500) - await expect(model.filter({ hasText: 'focus事件' })).toHaveCount(1) -}) + await expect(model.filter({ hasText: '触发 focus 事件' })).toHaveCount(1) + await expect(model.filter({ hasText: '触发 visible-change 事件' })).toHaveCount(1) -test('change', async ({ page }) => { - await page.goto('select#envts-change') - const model = page.locator('.tiny-modal') - const input = page.locator('#preview .tiny-input__inner') - - await input.click() - await page.getByRole('listitem').filter({ hasText: '黄金糕' }).click() + await option.first().click() await expect(input).toHaveValue('黄金糕') + await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(1) + await expect(model.filter({ hasText: '触发 visible-change 事件' })).toHaveCount(2) + await page.waitForTimeout(500) - await expect(model.filter({ hasText: 'changes事件' })).toHaveCount(1) + await wrap.click() + await expect(model.filter({ hasText: '触发 blur 事件' })).toHaveCount(1) + + await page.waitForTimeout(200) + await input.hover() + await select.locator('.tiny-select__close').click() + await page.waitForTimeout(500) + await expect(input).toHaveValue('') + await expect(model.filter({ hasText: '触发 clear 事件' })).toHaveCount(1) }) -test('clear', async ({ page }) => { - await page.goto('select#envts-change') +test('多选事件', async ({ page }) => { + await page.goto('select#events') + const wrap = page.locator('#events') + const select = wrap.locator('.tiny-select').nth(1) + const tag = wrap.locator('.tiny-tag') + const dropdown = page.locator('body > .tiny-select-dropdown') + const option = dropdown.locator('.tiny-option') const model = page.locator('.tiny-modal') - const input = page.locator('#preview .tiny-input__inner') - - await input.click() - await page.getByRole('listitem').filter({ hasText: '黄金糕' }).click() - await expect(input).toHaveValue('黄金糕') - input.hover() - await page.locator('#preview .tiny-input .tiny-input__suffix').click() - await page.waitForTimeout(500) - await expect(model.filter({ hasText: 'clear事件' })).toHaveCount(1) -}) - -test('blur', async ({ page }) => { - await page.goto('select#envts-change') - const model = page.locator('.tiny-modal') - const input = page.locator('#preview .tiny-input__inner') - - await input.click() - await input.blur() - await page.waitForTimeout(500) - await expect(model.filter({ hasText: 'blur事件' })).toHaveCount(1) -}) - -test('remove-tag', async ({ page }) => { - await page.goto('http://localhost:7130/pc/select/envts-remove') - const model = page.locator('.tiny-modal') - const select = page.locator('#preview .tiny-select') - const tags = page.locator('#preview .tiny-select .tiny-tag') await select.click() - await page.getByRole('listitem').filter({ hasText: '黄金糕' }).click() - await expect(tags.filter({ hasText: '黄金糕' })).toHaveCount(1) - await tags.filter({ hasText: '黄金糕' }).locator('.tiny-svg').click() - await page.waitForTimeout(500) - await expect(model.filter({ hasText: 'removeTag事件' })).toHaveCount(1) -}) + await expect(model.filter({ hasText: '触发 focus 事件' })).toHaveCount(1) + await expect(model.filter({ hasText: '触发 visible-change 事件' })).toHaveCount(1) -test('visible-change', async ({ page }) => { - await page.goto('http://localhost:7130/pc/select/envts-remove') - const model = page.locator('.tiny-modal') - const input = page.locator('#preview .tiny-input__inner') - const select = page.locator('#preview .tiny-select') + await option.nth(1).click() + await expect(tag).toHaveCount(1) + await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(1) + + await option.nth(0).click() + await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(2) + await expect(tag).toHaveCount(5) - await select.click() await page.waitForTimeout(500) - await expect(model.filter({ hasText: 'visibleChange事件' })).toHaveCount(1) - await input.blur() - await page.waitForTimeout(500) - await expect(model.filter({ hasText: 'visibleChange事件' })).toHaveCount(1) + await tag.first().locator('.tiny-tag__close').click() + await expect(model.filter({ hasText: '触发 blur 事件' })).toHaveCount(1) + await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(1) + await expect(model.filter({ hasText: '触发 remove-tag 事件' })).toHaveCount(1) + await expect(tag).toHaveCount(4) + + await wrap.click() + await expect(model.filter({ hasText: '触发 visible-change 事件' })).toHaveCount(1) + + await page.waitForTimeout(200) + await select.hover() + await select.locator('.tiny-select__close').click() + + await expect(tag).toHaveCount(0) + await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(1) }) diff --git a/examples/sites/demos/pc/app/select/events.vue b/examples/sites/demos/pc/app/select/events.vue index ae5673021..e4931b670 100644 --- a/examples/sites/demos/pc/app/select/events.vue +++ b/examples/sites/demos/pc/app/select/events.vue @@ -53,32 +53,33 @@ export default { methods: { change() { Modal.message({ - message: 'change 事件' + message: '触发 change 事件', + duration: 500 }) }, clear() { Modal.message({ - message: 'clear 事件' + message: '触发 clear 事件' }) }, focus() { Modal.message({ - message: 'focus 事件' + message: '触发 focus 事件' }) }, blur() { Modal.message({ - message: 'blur 事件' + message: '触发 blur 事件' }) }, removeTag() { Modal.message({ - message: 'remove-tag 事件' + message: '触发 remove-tag 事件' }) }, visibleChange() { Modal.message({ - message: 'visible-change 事件' + message: '触发 visible-change 事件' }) } } diff --git a/examples/sites/demos/pc/app/select/filter-method.spec.ts b/examples/sites/demos/pc/app/select/filter-method.spec.ts index 5cd26c794..7d9f7826f 100644 --- a/examples/sites/demos/pc/app/select/filter-method.spec.ts +++ b/examples/sites/demos/pc/app/select/filter-method.spec.ts @@ -1,50 +1,87 @@ import { expect, test } from '@playwright/test' -test('filter-nothing', async ({ page }) => { +test('默认搜索', async ({ page }) => { await page.goto('select#filter-method') - const input = page.locator('#preview .tiny-input__inner') + const wrap = page.locator('#filter-method') + const select = wrap.locator('.tiny-select').first() + const input = select.locator('.tiny-input__inner') + const dropdown = page.locator('body > .tiny-select-dropdown') + const option = dropdown.locator('.tiny-option') + // 1.1 没有过滤到内容 await input.click() + // 1.1.1 验证 no-match-text + await expect(page.getByText('No Match')).toBeHidden() await input.press('1') await expect(input).toHaveValue('1') await input.press('Enter') + await expect(page.getByText('No Match')).toBeVisible() - const listitems = await page.locator('.tiny-select-dropdown').getByRole('listitem').all() - listitems.forEach(async (item) => { - await expect(item).toHaveAttribute('display', 'none') + await page.waitForTimeout(500) + let allListItems = await option.all() + allListItems.forEach(async (item) => { + await expect(item).toHaveCSS('display', 'none') }) -}) -test('filter-something', async ({ page }) => { - await page.goto('select#filter-method') - const input = page.locator('#preview .tiny-input__inner') - - await input.click() + // 1.2 过滤到内容 await input.fill('双皮奶') await expect(input).toHaveValue('双皮奶') await input.press('Enter') - const listitems = await page - .locator('.tiny-select-dropdown') - .getByRole('listitem') - .filter({ hasNotText: '双皮奶' }) - .all() - listitems.forEach(async (item) => { - await expect(item).toHaveAttribute('display', 'none') + await page.waitForTimeout(200) + + allListItems.forEach(async (item) => { + const isVisibleItem = (await item.innerText()) === '双皮奶' + if (isVisibleItem) { + await expect(item).toHaveCSS('display', 'flex') + } else { + await expect(item).toHaveCSS('display', 'none') + } }) - await expect(page.locator('.tiny-select-dropdown').getByRole('listitem').filter({ hasText: '双皮奶' })).toBeVisible() - await page.locator('.tiny-select-dropdown').getByRole('listitem').filter({ hasText: '双皮奶' }).click() + await expect(option.filter({ hasText: '双皮奶' })).toBeVisible() + await option.filter({ hasText: '双皮奶' }).click() await expect(input).toHaveValue('双皮奶') }) -test('no-match-text', async ({ page }) => { - await page.goto('http://localhost:7130/pc/select/no-match-text') - const input = page.locator('#preview .tiny-input__inner') +test('自定义过滤', async ({ page }) => { + await page.goto('select#filter-method') + const wrap = page.locator('#filter-method') + const select = wrap.locator('.tiny-select').nth(1) + const input = select.locator('.tiny-input__inner') + const dropdown = page.locator('body > .tiny-select-dropdown') + const option = dropdown.locator('.tiny-option') + + // 1.1 没有过滤到内容 await input.click() - const listItems = page.locator('.tiny-select-dropdown__list').getByRole('listitem') - await expect((await listItems.all()).length).toEqual(5) - await expect(page.getByText('No Match')).toBeHidden() - await input.fill('1') + // 1.1.1 验证 no-match-text (待修复) + // await expect(page.getByText('No Match')).toBeHidden() + await input.press('1') + await expect(input).toHaveValue('1') await input.press('Enter') - await expect(page.getByText('No Match')).toBeVisible() + // await expect(page.getByText('No Match')).toBeVisible() + + await page.waitForTimeout(500) + let allListItems = await option.all() + allListItems.forEach(async (item) => { + await expect(item).toHaveCSS('display', 'none') + }) + + // 1.2 过滤到内容 + await input.fill('双皮奶') + await expect(input).toHaveValue('双皮奶') + await input.press('Enter') + + await page.waitForTimeout(200) + + allListItems.forEach(async (item) => { + const isVisibleItem = (await item.innerText()) === '双皮奶' + if (isVisibleItem) { + await expect(item).toHaveCSS('display', 'flex') + } else { + await expect(item).toHaveCSS('display', 'none') + } + }) + await expect(option.filter({ hasText: '双皮奶' })).toBeVisible() + await option.filter({ hasText: '双皮奶' }).click() + await expect(input).toHaveValue('双皮奶') }) diff --git a/examples/sites/demos/pc/app/select/hide-drop.spec.ts b/examples/sites/demos/pc/app/select/hide-drop.spec.ts index ea7599e4b..ee2213652 100644 --- a/examples/sites/demos/pc/app/select/hide-drop.spec.ts +++ b/examples/sites/demos/pc/app/select/hide-drop.spec.ts @@ -1,9 +1,10 @@ import { test, expect } from '@playwright/test' test('hidedrop', async ({ page }) => { - await page.goto('select#hide-select-input-border') - const select = page.locator('#preview .tiny-select').first() - const dropdown = page.locator('.tiny-select-dropdown') + await page.goto('select#hide-drop') + const wrap = page.locator('#hide-drop') + const select = wrap.locator('.tiny-select') + const dropdown = page.locator('body > .tiny-select-dropdown') await select.click() await expect(dropdown).toBeHidden() diff --git a/examples/sites/demos/pc/app/select/hide-drop.vue b/examples/sites/demos/pc/app/select/hide-drop.vue new file mode 100644 index 000000000..59cb03de3 --- /dev/null +++ b/examples/sites/demos/pc/app/select/hide-drop.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/examples/sites/demos/pc/app/select/input-box-type.spec.ts b/examples/sites/demos/pc/app/select/input-box-type.spec.ts index c9d07f773..3d674ccae 100644 --- a/examples/sites/demos/pc/app/select/input-box-type.spec.ts +++ b/examples/sites/demos/pc/app/select/input-box-type.spec.ts @@ -1,25 +1,68 @@ import { test, expect } from '@playwright/test' -test('default', async ({ page }) => { +test('下划线默认', async ({ page }) => { await page.goto('select#input-box-type') - const select = page.locator('#preview .tiny-select').first() + const wrap = page.locator('#input-box-type') + const select = wrap.locator('.tiny-select').nth(0) + const input = select.locator('.tiny-input__inner') + const dropdown = page.locator('body > .tiny-select-dropdown') + const option = dropdown.locator('.tiny-option') await expect(select).toHaveClass(/tiny-select__underline/) + await expect(input).toHaveCSS('border-top-width', '0px') + await expect(input).toHaveCSS('border-left-width', '0px') + await expect(input).toHaveCSS('border-right-width', '0px') + await expect(input).toHaveCSS('border-color', 'rgb(173, 176, 184)') + await expect(select.locator('svg')).toHaveCSS('fill', 'rgb(87, 93, 108)') + + await select.click() + await option.first().click() + await expect(dropdown).toBeHidden() + await expect(input).toHaveValue('黄金糕') }) -test('disable', async ({ page }) => { +test('下划线禁用', async ({ page }) => { await page.goto('select#input-box-type') - const select = page.locator('#preview .tiny-select').nth(1) + const wrap = page.locator('#input-box-type') + const select = wrap.locator('.tiny-select').nth(1) const input = select.locator('.tiny-input__inner') + const dropdown = page.locator('body > .tiny-select-dropdown') await expect(select).toHaveClass(/tiny-select__underline/) + await expect(input).toHaveCSS('border-top-width', '0px') + await expect(input).toHaveCSS('border-left-width', '0px') + await expect(input).toHaveCSS('border-right-width', '0px') + await expect(input).toHaveCSS('border-color', 'rgb(223, 225, 230)') + await expect(input).toHaveCSS('cursor', 'not-allowed') + await expect(select.locator('svg')).toHaveCSS('fill', 'rgb(173, 176, 184)') const hasDisabled = await input.evaluate((input) => input.hasAttribute('disabled')) await expect(hasDisabled).toBe(true) + + await select.click() + await expect(dropdown).toBeHidden() + await expect(input).toHaveValue('') }) -test('multiple', async ({ page }) => { +test('下划线多选', async ({ page }) => { await page.goto('select#input-box-type') - const select = page.locator('#preview .tiny-select').nth(2) + const wrap = page.locator('#input-box-type') + const select = wrap.locator('.tiny-select').nth(2) + const input = select.locator('.tiny-input__inner') + const tag = wrap.locator('.tiny-tag') + const dropdown = page.locator('body > .tiny-select-dropdown') + const option = dropdown.locator('.tiny-option') + + await expect(select).toHaveClass(/tiny-select__underline/) + await expect(input).toHaveCSS('border-top-width', '0px') + await expect(input).toHaveCSS('border-left-width', '0px') + await expect(input).toHaveCSS('border-right-width', '0px') + await expect(input).toHaveCSS('border-color', 'rgb(173, 176, 184)') + await expect(select.locator('.tiny-select__caret')).toHaveCSS('fill', 'rgb(87, 93, 108)') + + await select.click() + await expect(dropdown).toBeVisible() + await option.first().click() + await expect(tag).toHaveCount(5) await expect(select).toHaveClass(/tiny-select__underline/) await expect(select).toHaveClass(/tiny-select__multiple/) diff --git a/examples/sites/demos/pc/app/select/is-drop-inherit-width.spec.ts b/examples/sites/demos/pc/app/select/is-drop-inherit-width.spec.ts index e95c2d38e..ec1798682 100644 --- a/examples/sites/demos/pc/app/select/is-drop-inherit-width.spec.ts +++ b/examples/sites/demos/pc/app/select/is-drop-inherit-width.spec.ts @@ -1,29 +1,34 @@ import { expect, test } from '@playwright/test' -test('not-inherit-width', async ({ page }) => { +test('默认下拉弹框宽度由内容撑开', async ({ page }) => { await page.goto('select#is-drop-inherit-width') - const input = page.getByPlaceholder('请选择').first() - await input.click() - await page.waitForTimeout(1000) - const listitem = page.getByRole('listitem').filter({ hasText: '双皮奶' }) - const inputBox = await input.boundingBox() - const listitemBox = await listitem.boundingBox() - await page.waitForTimeout(3000) + const wrap = page.locator('#is-drop-inherit-width') + const select = wrap.locator('.tiny-select').nth(0) + const dropdown = page.locator('body > .tiny-select-dropdown') + const input = select.locator('.tiny-input__inner') + const option = dropdown.locator('.tiny-option') + + await select.click() + const inputBox = await input.boundingBox() + const listitemBox = await option.first().boundingBox() + const result = listitemBox.width > inputBox.width await expect(result).toBe(true) }) -test('inherit-width', async ({ page }) => { +test('下拉弹框宽度与输入框一致', async ({ page }) => { await page.goto('select#is-drop-inherit-width') - const input = page.getByPlaceholder('请选择').nth(1) - await input.click() - await page.waitForTimeout(1000) - const listitem = page.getByRole('listitem').filter({ hasText: '双皮奶' }) - const inputBox = await input.boundingBox() + const wrap = page.locator('#is-drop-inherit-width') + const select = wrap.locator('.tiny-select').nth(1) + const dropdown = page.locator('body > .tiny-select-dropdown') + const input = select.locator('.tiny-input__inner') + const option = dropdown.locator('.tiny-option') + + await select.click() + const inputBox = await input.boundingBox() + const listitemBox = await option.first().boundingBox() - const listitemBox = await listitem.boundingBox() - await page.waitForTimeout(3000) const result = listitemBox.width === inputBox.width await expect(result).toBe(true) }) diff --git a/examples/sites/demos/pc/app/select/manual-focus-blur-composition-api.vue b/examples/sites/demos/pc/app/select/manual-focus-blur-composition-api.vue index 85e911290..625165f3a 100644 --- a/examples/sites/demos/pc/app/select/manual-focus-blur-composition-api.vue +++ b/examples/sites/demos/pc/app/select/manual-focus-blur-composition-api.vue @@ -1,7 +1,9 @@