From 421660ab1171f998eb4797f606ddb4e1a6f72e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=B2=A9=E5=B2=A9?= Date: Thu, 23 Jul 2026 11:45:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=20facetime=20?= =?UTF-8?q?=E2=80=94=20=E5=A3=B0=E6=98=8E=E5=BC=8F=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=EF=BC=88=E8=81=94=E7=B3=BB=E4=BA=BA/=E5=91=BC=E5=8F=AB/?= =?UTF-8?q?=E9=9D=99=E9=9F=B3/=E7=BB=93=E6=9D=9F=EF=BC=89+=207=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apps/facetime/FaceTime.vue | 120 ++++++++++++++++++-------------- tests/cases/34-facetime.test.ts | 33 +++++++++ 2 files changed, 101 insertions(+), 52 deletions(-) create mode 100644 tests/cases/34-facetime.test.ts diff --git a/src/apps/facetime/FaceTime.vue b/src/apps/facetime/FaceTime.vue index c2da5d5..4610cf6 100644 --- a/src/apps/facetime/FaceTime.vue +++ b/src/apps/facetime/FaceTime.vue @@ -1,75 +1,91 @@ diff --git a/tests/cases/34-facetime.test.ts b/tests/cases/34-facetime.test.ts new file mode 100644 index 0000000..51235fe --- /dev/null +++ b/tests/cases/34-facetime.test.ts @@ -0,0 +1,33 @@ +/** + * 34-facetime: FaceTime Vue 组件化测试 + */ +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' +import { h, render, nextTick } from 'vue' +import FaceTimeComponent from '../../src/apps/facetime/FaceTime.vue' +import { store } from '../../src/composables/useStore' +import { setupDOM } from '../helpers' + +function makeMockWin() { + const el = document.createElement('div'); el.className = 'window' + document.getElementById('window-layer')?.appendChild(el) + const body = document.createElement('div'); body.className = 'win-body' + el.appendChild(body) + return { id: 'ft', appId: 'facetime', el, body, timers: [] as any[], data: {} } +} + +describe('34-facetime — FaceTime Vue 组件化', () => { + let win: any + beforeEach(() => { setupDOM(); win = makeMockWin() + store.set('contacts', [{ id: '1', name: '测试人', phone: '123', email: 't@t.com', note: '' }]) + }) + afterEach(() => { render(null, win.body); win.el.remove() }) + function mount() { const v = h(FaceTimeComponent, { win }); render(v, win.body) } + + it('显示联系人选择界面', () => { mount(); expect(document.querySelector('.ft-grid')).toBeTruthy() }) + it('联系人列表包含联系人', () => { mount(); expect(document.querySelectorAll('.ft-cell').length).toBeGreaterThanOrEqual(1) }) + it('点击呼叫开始拨打', async () => { mount(); (document.querySelector('.btn.primary') as HTMLElement)?.dispatchEvent(new MouseEvent('click', { bubbles: true })); await nextTick(); expect(document.querySelector('.ft-status')?.textContent).toContain('正在呼叫') }) + it('麦克风静音切换', async () => { mount(); (document.querySelector('.btn.primary') as HTMLElement)?.dispatchEvent(new MouseEvent('click', { bubbles: true })); await nextTick(); const micBtn = document.querySelector('.ft-ctl') as HTMLElement; micBtn?.dispatchEvent(new MouseEvent('click', { bubbles: true })); await nextTick(); expect(micBtn?.classList.contains('off')).toBe(true) }) + it('视频关闭切换', async () => { mount(); (document.querySelector('.btn.primary') as HTMLElement)?.dispatchEvent(new MouseEvent('click', { bubbles: true })); await nextTick(); const camBtn = document.querySelectorAll('.ft-ctl')[1] as HTMLElement; camBtn?.dispatchEvent(new MouseEvent('click', { bubbles: true })); await nextTick(); expect(camBtn?.classList.contains('off')).toBe(true) }) + it('结束通话回到空闲', async () => { vi.useFakeTimers(); mount(); (document.querySelector('.btn.primary') as HTMLElement)?.dispatchEvent(new MouseEvent('click', { bubbles: true })); await nextTick(); const endBtn = document.querySelector('.ft-ctl.end') as HTMLElement; endBtn?.dispatchEvent(new MouseEvent('click', { bubbles: true })); await nextTick(); expect(document.querySelector('.ft-status')?.textContent).toContain('通话已结束'); vi.advanceTimersByTime(1500); await nextTick(); expect(document.querySelector('.ft-grid')).toBeTruthy(); vi.useRealTimers() }) + it('卸载', () => { mount(); render(null, win.body); expect(win.body.children.length).toBe(0) }) +})