@@ -1,4 +1,4 @@
1-import { describe, it, expect } from 'vitest'
1+import { describe, it, expect, vi } from 'vitest'
22import { axe } from 'vitest-axe'
33import { mountSuspended } from '@nuxt/test-utils/runtime'
44import { renderEach } from '../component-render'
@@ -21,6 +21,57 @@ describe('ChatPrompt', () => {
2121['with footer slot', { slots: { footer: () => 'Footer slot' } }]
2222])
232324+it('emits submit on Enter', async () => {
25+const wrapper = await mountSuspended(ChatPrompt, {
26+props: { modelValue: 'Hello' }
27+})
28+29+const textarea = wrapper.find('textarea')
30+await textarea.trigger('keydown', { key: 'Enter' })
31+32+expect(wrapper.emitted('submit')).toHaveLength(1)
33+})
34+35+it('does not emit submit on Enter during composition', async () => {
36+const wrapper = await mountSuspended(ChatPrompt, {
37+props: { modelValue: 'Hello' }
38+})
39+40+const textarea = wrapper.find('textarea')
41+await textarea.trigger('keydown', { key: 'Enter', isComposing: true })
42+43+expect(wrapper.emitted('submit')).toBeUndefined()
44+})
45+46+it('does not emit submit on Enter immediately after compositionend', async () => {
47+const wrapper = await mountSuspended(ChatPrompt, {
48+props: { modelValue: 'Hello' }
49+})
50+51+const textarea = wrapper.find('textarea')
52+await textarea.trigger('compositionend')
53+await textarea.trigger('keydown', { key: 'Enter' })
54+55+expect(wrapper.emitted('submit')).toBeUndefined()
56+})
57+58+it('re-enables submit after compositionend cooldown', async () => {
59+vi.useFakeTimers()
60+61+const wrapper = await mountSuspended(ChatPrompt, {
62+props: { modelValue: 'Hello' }
63+})
64+65+const textarea = wrapper.find('textarea')
66+await textarea.trigger('compositionend')
67+vi.advanceTimersByTime(50)
68+await textarea.trigger('keydown', { key: 'Enter' })
69+70+expect(wrapper.emitted('submit')).toHaveLength(1)
71+72+vi.useRealTimers()
73+})
74+2475it('passes accessibility tests', async () => {
2576const wrapper = await mountSuspended(ChatPrompt, {
2677props: {