refactor(vue): use test id directive
This commit is contained in:
parent
50a4e1bf93
commit
744f0a0f42
|
|
@ -48,6 +48,7 @@ export { useNodeFontStatus } from '#vue/shared/font-status/use'
|
|||
export { usePropScrub } from '#vue/controls/prop-scrub/use'
|
||||
export { toolCursor } from '#vue/editor/tool-cursor'
|
||||
export { testId, testIdSelector } from '#vue/testing/test-id'
|
||||
export { vTestId } from '#vue/testing/v-test-id'
|
||||
export type {
|
||||
RequiredTestIdProps,
|
||||
TestId,
|
||||
|
|
|
|||
17
packages/vue/src/testing/v-test-id.ts
Normal file
17
packages/vue/src/testing/v-test-id.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { Directive } from 'vue'
|
||||
|
||||
import type { TestId } from './test-id'
|
||||
|
||||
function applyTestId(el: HTMLElement, value?: TestId | null) {
|
||||
if (value) el.setAttribute('data-test-id', value)
|
||||
else el.removeAttribute('data-test-id')
|
||||
}
|
||||
|
||||
export const vTestId: Directive<HTMLElement, TestId | null | undefined> = {
|
||||
mounted(el, binding) {
|
||||
applyTestId(el, binding.value)
|
||||
},
|
||||
updated(el, binding) {
|
||||
applyTestId(el, binding.value)
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ import {
|
|||
|
||||
import IconChevronRight from '~icons/lucide/chevron-right'
|
||||
|
||||
import { testId as testIdAttr, useI18n } from '@open-pencil/vue'
|
||||
import { vTestId, useI18n } from '@open-pencil/vue'
|
||||
import { useMenuUI } from '@/components/ui/menu'
|
||||
import { IS_TAURI } from '@/constants'
|
||||
import { useAppMenu } from '@/app/shell/menu/app-menu'
|
||||
|
|
@ -91,7 +91,7 @@ const subMenuCls = useMenuUI({ content: 'min-w-44' })
|
|||
<MenubarRoot class="scrollbar-none flex items-center gap-0.5 overflow-x-auto">
|
||||
<MenubarMenu v-for="menu in topMenus" :key="menu.label">
|
||||
<MenubarTrigger
|
||||
v-bind="testIdAttr(`menubar-${menu.label.toLowerCase()}`)"
|
||||
v-test-id="`menubar-${menu.label.toLowerCase()}`"
|
||||
class="flex cursor-pointer items-center rounded px-2 py-1 text-xs text-muted transition-colors select-none hover:bg-hover hover:text-surface data-[state=open]:bg-hover data-[state=open]:text-surface"
|
||||
>
|
||||
{{ menu.label }}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
ContextMenuPortal
|
||||
} from 'reka-ui'
|
||||
import {
|
||||
testId as testIdAttr,
|
||||
vTestId,
|
||||
useEditorCommands,
|
||||
useI18n,
|
||||
useMenuModel,
|
||||
|
|
@ -126,7 +126,7 @@ const contextCommandTestIds: Record<string, string> = {
|
|||
</ContextMenuSub>
|
||||
<ContextMenuItem
|
||||
v-else
|
||||
v-bind="testIdAttr(item.id ? contextCommandTestIds[item.id] : undefined)"
|
||||
v-test-id="item.id ? contextCommandTestIds[item.id] : undefined"
|
||||
:class="canvasMenuItemClass(item.label, cls)"
|
||||
:disabled="item.disabled"
|
||||
@select="item.action?.()"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { inputNumberValue, testId as testIdAttr, type TestIdProps } from '@open-pencil/vue'
|
||||
import { inputNumberValue, vTestId, type TestIdProps } from '@open-pencil/vue'
|
||||
import { usePickerSliderUI } from './ui/picker-slider'
|
||||
|
||||
type PickerSliderDisplay = {
|
||||
|
|
@ -64,7 +64,7 @@ function thumbLeft(): string {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cls.root" v-bind="testIdAttr(testId)">
|
||||
<div :class="cls.root" v-test-id="testId">
|
||||
<span :class="cls.label">{{ label }}</span>
|
||||
<div :class="cls.track">
|
||||
<div :class="cls.gradient" :style="gradientStyle" />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { testId as testIdAttr, type RequiredTestIdProps } from '@open-pencil/vue'
|
||||
import { vTestId, type RequiredTestIdProps } from '@open-pencil/vue'
|
||||
import type { Component } from 'vue'
|
||||
|
||||
interface ToolButtonProps extends RequiredTestIdProps {
|
||||
|
|
@ -22,7 +22,7 @@ const emit = defineEmits<{
|
|||
|
||||
<template>
|
||||
<button
|
||||
v-bind="testIdAttr(testId)"
|
||||
v-test-id="testId"
|
||||
class="flex size-8 cursor-pointer items-center justify-center border-none transition-colors"
|
||||
:class="[
|
||||
mobile ? 'rounded-[6px] select-none' : 'rounded-lg',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import IconChevronDown from '~icons/lucide/chevron-down'
|
|||
|
||||
import { menu } from '@/components/ui/menu'
|
||||
import ToolButton from '@/components/Toolbar/ToolButton.vue'
|
||||
import { testId as testIdAttr, ToolbarItem } from '@open-pencil/vue'
|
||||
import { vTestId, ToolbarItem } from '@open-pencil/vue'
|
||||
|
||||
import type { Tool } from '@open-pencil/vue'
|
||||
import type { EditorToolDef } from '@open-pencil/core/editor'
|
||||
|
|
@ -69,7 +69,7 @@ function activeKeyForTool() {
|
|||
<DropdownMenuRoot>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<button
|
||||
v-bind="testIdAttr(`${mobile ? 'mobile-' : ''}toolbar-flyout-${tool.key.toLowerCase()}`)"
|
||||
v-test-id="`${mobile ? 'mobile-' : ''}toolbar-flyout-${tool.key.toLowerCase()}`"
|
||||
class="flex h-8 w-3 cursor-pointer items-center justify-center border-none transition-colors"
|
||||
:class="[
|
||||
mobile ? 'rounded-[6px] select-none' : 'rounded-lg',
|
||||
|
|
@ -93,7 +93,7 @@ function activeKeyForTool() {
|
|||
:tool="sub"
|
||||
>
|
||||
<DropdownMenuItem
|
||||
v-bind="testIdAttr(`${mobile ? 'mobile-' : ''}toolbar-flyout-item-${sub.toLowerCase()}`)"
|
||||
v-test-id="`${mobile ? 'mobile-' : ''}toolbar-flyout-item-${sub.toLowerCase()}`"
|
||||
:class="menu().item({ class: subActive ? 'bg-accent text-white' : undefined })"
|
||||
@select="actions.select"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { testId as testIdAttr } from '@open-pencil/vue'
|
||||
import { vTestId } from '@open-pencil/vue'
|
||||
|
||||
import type { ToolbarActionItem } from '@/components/Toolbar/types'
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ const emit = defineEmits<{
|
|||
<button
|
||||
v-for="item in actions"
|
||||
:key="item.label"
|
||||
v-bind="testIdAttr(`${testPrefix}-${item.label.toLowerCase()}`)"
|
||||
v-test-id="`${testPrefix}-${item.label.toLowerCase()}`"
|
||||
class="flex size-8 cursor-pointer items-center justify-center rounded-[6px] border-none bg-transparent text-muted transition-colors select-none active:bg-hover active:text-surface"
|
||||
@click="emit('action', item)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import {
|
|||
} from 'reka-ui'
|
||||
import { FlexRender } from '@tanstack/vue-table'
|
||||
|
||||
import { testId as testIdAttr, useI18n, useVariablesEditor } from '@open-pencil/vue'
|
||||
import { vTestId, useI18n, useVariablesEditor } from '@open-pencil/vue'
|
||||
|
||||
import IconHash from '~icons/lucide/hash'
|
||||
import IconPalette from '~icons/lucide/palette'
|
||||
|
|
@ -390,7 +390,7 @@ function modeId(columnId: string): string {
|
|||
v-for="item in variableTypes"
|
||||
:key="item.type"
|
||||
:class="menuCls.item"
|
||||
v-bind="testIdAttr(`variables-add-${item.type.toLowerCase()}`)"
|
||||
v-test-id="`variables-add-${item.type.toLowerCase()}`"
|
||||
@select="ctx.addVariable(item.type)"
|
||||
>
|
||||
<component :is="variableTypeIcons[item.type]" :class="menuCls.icon" />
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
AlertDialogTitle
|
||||
} from 'reka-ui'
|
||||
import { computed } from 'vue'
|
||||
import { testId as testIdAttr } from '@open-pencil/vue'
|
||||
import { vTestId } from '@open-pencil/vue'
|
||||
|
||||
import {
|
||||
currentPermission,
|
||||
|
|
@ -86,7 +86,7 @@ function handleDismiss() {
|
|||
<AlertDialogAction
|
||||
v-for="opt in allowOptions"
|
||||
:key="opt.optionId"
|
||||
v-bind="testIdAttr(`acp-permission-option-${opt.kind}`)"
|
||||
v-test-id="`acp-permission-option-${opt.kind}`"
|
||||
class="w-full rounded bg-accent px-3 py-1.5 text-xs font-medium text-white hover:bg-accent/90"
|
||||
@click="respondToPermission(opt.optionId)"
|
||||
>
|
||||
|
|
@ -96,7 +96,7 @@ function handleDismiss() {
|
|||
<AlertDialogCancel
|
||||
v-for="opt in rejectOptions"
|
||||
:key="opt.optionId"
|
||||
v-bind="testIdAttr(`acp-permission-option-${opt.kind}`)"
|
||||
v-test-id="`acp-permission-option-${opt.kind}`"
|
||||
class="w-full rounded border border-border bg-canvas px-3 py-1.5 text-xs text-muted hover:bg-hover hover:text-surface"
|
||||
@click="respondToPermission(opt.optionId)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { isTextUIPart, isToolUIPart, getToolName } from 'ai'
|
||||
import { CollapsibleContent, CollapsibleRoot, CollapsibleTrigger } from 'reka-ui'
|
||||
import { Markdown } from 'vue-stream-markdown'
|
||||
import { testId as testIdAttr } from '@open-pencil/vue'
|
||||
import { vTestId } from '@open-pencil/vue'
|
||||
import 'vue-stream-markdown/index.css'
|
||||
|
||||
import type { UIDataTypes, UIMessage, UIMessagePart, UITools } from 'ai'
|
||||
|
|
@ -41,7 +41,7 @@ function partKey(part: UIMessagePart<UIDataTypes, UITools>, index: number): stri
|
|||
|
||||
<template>
|
||||
<div
|
||||
v-bind="testIdAttr(`chat-message-${message.role}`)"
|
||||
v-test-id="`chat-message-${message.role}`"
|
||||
:class="message.role === 'user' ? 'flex justify-end' : ''"
|
||||
>
|
||||
<div class="min-w-0 space-y-1.5" :class="message.role === 'user' ? 'max-w-[85%]' : ''">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { testId as testIdAttr, type TestIdProps } from '@open-pencil/vue'
|
||||
import { vTestId, type TestIdProps } from '@open-pencil/vue'
|
||||
|
||||
import Tip from '@/components/ui/Tip.vue'
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ const emit = defineEmits<{
|
|||
<template>
|
||||
<Tip :label="label">
|
||||
<button
|
||||
v-bind="testIdAttr(testId)"
|
||||
v-test-id="testId"
|
||||
class="shrink-0 cursor-pointer border-none bg-transparent p-0 text-violet-400 hover:text-surface"
|
||||
@click="emit('detach')"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import BoundVariableButton from '@/components/properties/BoundVariableButton.vue
|
|||
import VariablePickerPopover from '@/components/properties/VariablePickerPopover.vue'
|
||||
import { useIconButtonUI } from '@/components/ui/icon-button'
|
||||
|
||||
import { testId as testIdAttr, useI18n } from '@open-pencil/vue'
|
||||
import { vTestId, useI18n } from '@open-pencil/vue'
|
||||
|
||||
import {
|
||||
opacityFromPercent,
|
||||
|
|
@ -99,7 +99,7 @@ const { panels, dialogs } = useI18n()
|
|||
/>
|
||||
|
||||
<button
|
||||
v-bind="testIdAttr(visibilityTestId)"
|
||||
v-test-id="visibilityTestId"
|
||||
:data-visible="item.visible ? 'true' : 'false'"
|
||||
class="shrink-0 cursor-pointer border-none bg-transparent p-0 text-muted hover:text-surface"
|
||||
@click="emit('toggleVisibility')"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import ColorInput from '@/components/ColorPicker/ColorInput.vue'
|
|||
import ScrubInput from '@/components/ScrubInput.vue'
|
||||
import { useIconButtonUI } from '@/components/ui/icon-button'
|
||||
import { useSectionUI } from '@/components/ui/section'
|
||||
import { PropertyListRoot, testId as testIdAttr, useEffectsControls, useI18n } from '@open-pencil/vue'
|
||||
import { PropertyListRoot, vTestId, useEffectsControls, useI18n } from '@open-pencil/vue'
|
||||
|
||||
import { colorToCSS } from '@open-pencil/core/color'
|
||||
|
||||
|
|
@ -65,7 +65,7 @@ const sectionCls = useSectionUI()
|
|||
/>
|
||||
|
||||
<button
|
||||
v-bind="testIdAttr(`effect-visibility-${i}`)"
|
||||
v-test-id="`effect-visibility-${i}`"
|
||||
:data-visible="effect.visible ? 'true' : 'false'"
|
||||
class="cursor-pointer border-none bg-transparent p-0 text-muted hover:text-surface"
|
||||
@click="actions.toggleVisibility(i)"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import Tip from '@/components/ui/Tip.vue'
|
||||
import { testId as testIdAttr, useI18n, useLayoutControlsContext } from '@open-pencil/vue'
|
||||
import { vTestId, useI18n, useLayoutControlsContext } from '@open-pencil/vue'
|
||||
|
||||
import type { LayoutMode } from '@open-pencil/core/scene-graph'
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ const layoutModes: { mode: LayoutMode; test: string }[] = [
|
|||
<button
|
||||
v-for="dir in layoutModes"
|
||||
:key="dir.mode"
|
||||
v-bind="testIdAttr(`layout-direction-${dir.test}`)"
|
||||
v-test-id="`layout-direction-${dir.test}`"
|
||||
class="flex cursor-pointer items-center justify-center rounded border px-2 py-1"
|
||||
:class="
|
||||
(dir.mode === 'GRID' ? ctx.isGrid : ctx.node.layoutMode === dir.mode)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import VariablePickerPopover from '@/components/properties/VariablePickerPopover
|
|||
import { useSelectUI } from '@/components/ui/select'
|
||||
import {
|
||||
testId as testIdAttr,
|
||||
vTestId,
|
||||
useI18n,
|
||||
useLayoutControlsContext,
|
||||
useNumberVariableBinding
|
||||
|
|
@ -361,7 +362,7 @@ function handleSizeSelect(axis: 'width' | 'height', value: SizeSelectValue) {
|
|||
@update:model-value="(value) => handleLimitSelect(item.prop, value as string)"
|
||||
>
|
||||
<SelectTrigger
|
||||
v-bind="testIdAttr(`${item.testId}-menu`)"
|
||||
v-test-id="`${item.testId}-menu`"
|
||||
:reference="limitFieldAnchor(index)"
|
||||
class="flex shrink-0 cursor-pointer items-center self-stretch border-none bg-transparent px-1 text-[11px] text-muted outline-none"
|
||||
@pointerdown.stop
|
||||
|
|
@ -403,7 +404,7 @@ function handleSizeSelect(axis: 'width' | 'height', value: SizeSelectValue) {
|
|||
@update:model-value="(value) => handleLimitSelect(item.prop, value as string)"
|
||||
>
|
||||
<SelectTrigger
|
||||
v-bind="testIdAttr(`${item.testId}-menu`)"
|
||||
v-test-id="`${item.testId}-menu`"
|
||||
:reference="limitFieldAnchor(index)"
|
||||
class="flex shrink-0 cursor-pointer items-center self-stretch border-none bg-transparent px-1 text-[11px] text-muted outline-none"
|
||||
@pointerdown.stop
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
|
||||
import { testId as testIdAttr } from '@open-pencil/vue'
|
||||
import { vTestId } from '@open-pencil/vue'
|
||||
|
||||
import type { Variable } from '@open-pencil/core/scene-graph'
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ function submitCreate() {
|
|||
<template>
|
||||
<PopoverRoot v-model:open="open">
|
||||
<PopoverTrigger
|
||||
v-bind="testIdAttr(triggerTestId)"
|
||||
v-test-id="triggerTestId"
|
||||
:aria-label="triggerLabel"
|
||||
:title="triggerLabel"
|
||||
class="shrink-0 cursor-pointer border-none bg-transparent p-0 text-muted hover:text-surface"
|
||||
|
|
@ -146,7 +146,7 @@ function submitCreate() {
|
|||
class="min-w-0 flex-1 rounded border border-border bg-transparent px-1.5 py-1 text-[11px] text-surface outline-none placeholder:text-muted focus:border-accent"
|
||||
/>
|
||||
<button
|
||||
v-bind="testIdAttr(createTestId)"
|
||||
v-test-id="createTestId"
|
||||
:disabled="!canCreate"
|
||||
class="rounded border border-border bg-panel px-1.5 py-1 text-[11px] text-surface hover:bg-hover disabled:cursor-not-allowed disabled:opacity-50"
|
||||
type="submit"
|
||||
|
|
@ -156,7 +156,7 @@ function submitCreate() {
|
|||
</form>
|
||||
<button
|
||||
v-else
|
||||
v-bind="testIdAttr(createTestId)"
|
||||
v-test-id="createTestId"
|
||||
class="flex w-full cursor-pointer items-center gap-1.5 bg-transparent px-2 py-1.5 text-left text-[11px] text-muted hover:bg-hover hover:text-surface"
|
||||
@click="startCreate"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
SelectTrigger,
|
||||
SelectViewport
|
||||
} from 'reka-ui'
|
||||
import { testId as testIdAttr, type TestIdProps } from '@open-pencil/vue'
|
||||
import { vTestId, type TestIdProps } from '@open-pencil/vue'
|
||||
|
||||
import { useSelectUI } from '@/components/ui/select'
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ const separator = ui?.separator ?? 'mx-1 my-1 h-px bg-border'
|
|||
|
||||
<template>
|
||||
<SelectRoot v-model="modelValue">
|
||||
<SelectTrigger v-bind="testIdAttr(testId)" :class="select.trigger">
|
||||
<SelectTrigger v-test-id="testId" :class="select.trigger">
|
||||
<slot name="value">{{ displayValue }}</slot>
|
||||
<icon-lucide-chevron-down class="size-2.5 shrink-0 text-muted" />
|
||||
</SelectTrigger>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
SelectViewport
|
||||
} from 'reka-ui'
|
||||
|
||||
import { testId as testIdAttr, type TestIdProps } from '@open-pencil/vue'
|
||||
import { vTestId, type TestIdProps } from '@open-pencil/vue'
|
||||
|
||||
import { useSelectUI } from '@/components/ui/select'
|
||||
import type { SelectUi } from '@/components/ui/select'
|
||||
|
|
@ -47,7 +47,7 @@ const indicator = ui?.indicator ?? 'absolute left-1.5 inline-flex items-center j
|
|||
|
||||
<template>
|
||||
<SelectRoot v-model="modelValue">
|
||||
<SelectTrigger v-bind="testIdAttr(testId)" :class="select.trigger">
|
||||
<SelectTrigger v-test-id="testId" :class="select.trigger">
|
||||
<SelectValue :placeholder="placeholder" />
|
||||
<icon-lucide-chevron-down class="ml-1 size-3 shrink-0 text-muted" />
|
||||
</SelectTrigger>
|
||||
|
|
|
|||
Loading…
Reference in a new issue