useShare.test.js 4.84 KB
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'

const wxMocks = vi.hoisted(() => ({
  wxReady: vi.fn(callback => callback()),
  updateAppMessageShareData: vi.fn(),
  updateTimelineShareData: vi.fn(),
  onMenuShareWeibo: vi.fn(),
}))

vi.mock('weixin-js-sdk', () => ({
  default: {
    ready: wxMocks.wxReady,
    updateAppMessageShareData: wxMocks.updateAppMessageShareData,
    updateTimelineShareData: wxMocks.updateTimelineShareData,
    onMenuShareWeibo: wxMocks.onMenuShareWeibo,
  },
}))

vi.mock('@/utils/tools', () => ({
  wxInfo: () => ({
    isWeiXin: true,
  }),
}))

import { installWxShareSync, normalizeShareImageUrl, resolveRouteShareData } from '../useShare'

const createRouterMock = (initialRoute = { meta: { title: '首页' } }) => {
  let afterEachHook = null

  return {
    currentRoute: { value: initialRoute },
    afterEach: vi.fn(handler => {
      afterEachHook = handler
      return () => {
        afterEachHook = null
      }
    }),
    triggerAfterEach(route) {
      this.currentRoute.value = route
      afterEachHook?.(route)
    },
  }
}

const flushMutationObserver = async () => {
  await new Promise(resolve => setTimeout(resolve, 0))
}

describe('useShare', () => {
  beforeEach(() => {
    document.head.innerHTML = '<title>美乐爱觉</title>'
    document.title = '美乐爱觉'
    window.location.hash = '#/'
    wxMocks.wxReady.mockClear()
    wxMocks.updateAppMessageShareData.mockClear()
    wxMocks.updateTimelineShareData.mockClear()
    wxMocks.onMenuShareWeibo.mockClear()
  })

  afterEach(() => {
    vi.clearAllMocks()
  })

  it('根据路由 meta 解析分享数据', () => {
    const shareData = resolveRouteShareData({
      meta: {
        title: '课程详情',
        shareDesc: '课程简介',
        shareImage: 'https://cdn.ipadbiz.cn/mlaj/course-cover.png',
      },
    })

    expect(shareData.title).toBe('课程详情')
    expect(shareData.desc).toBe('课程简介')
    expect(shareData.imgUrl).toContain('imageMogr2/thumbnail/200x/strip/quality/70')
    expect(shareData.link).toBe(window.location.href)
  })

  it('未提供描述时不再回退为标题', () => {
    const shareData = resolveRouteShareData({
      meta: {
        title: '课程详情',
      },
    })

    expect(shareData.title).toBe('课程详情')
    expect(shareData.desc).toBe('')
  })

  it('在路由切换和标题变化时同步微信分享数据', async () => {
    const router = createRouterMock({
      meta: { title: '首页' },
    })

    const teardown = installWxShareSync(router, { isEnabled: true })

    await flushMutationObserver()

    expect(wxMocks.updateAppMessageShareData).toHaveBeenCalled()
    expect(wxMocks.updateAppMessageShareData.mock.lastCall[0].title).toBe('美乐爱觉')

    window.location.hash = '#/courses/2'
    router.triggerAfterEach({
      meta: {
        title: '课程详情',
        shareDesc: '课程简介',
      },
    })

    await flushMutationObserver()

    expect(wxMocks.updateAppMessageShareData.mock.lastCall[0]).toMatchObject({
      title: '课程详情',
      desc: '课程简介',
      link: window.location.href,
    })
    expect(wxMocks.updateTimelineShareData.mock.lastCall[0].title).toBe('课程详情')

    document.title = '高阶课程'
    await flushMutationObserver()

    expect(wxMocks.updateAppMessageShareData.mock.lastCall[0].title).toBe('高阶课程')
    expect(wxMocks.updateAppMessageShareData.mock.lastCall[0].desc).toBe('课程简介')

    teardown()
  })

  it('支持通过异步 resolver 合并分享描述与图片', async () => {
    const router = createRouterMock({
      meta: { title: '课程详情' },
    })

    installWxShareSync(router, {
      isEnabled: true,
      resolver: vi.fn(() =>
        Promise.resolve({
          desc: '课程副标题',
          imgUrl: 'https://cdn.ipadbiz.cn/mlaj/course-cover.png',
        })
      ),
    })

    await flushMutationObserver()

    expect(wxMocks.updateAppMessageShareData.mock.lastCall[0].desc).toBe('课程副标题')
    expect(wxMocks.updateAppMessageShareData.mock.lastCall[0].imgUrl).toContain(
      'imageMogr2/thumbnail/200x/strip/quality/70'
    )
  })

  it('resolver 显式返回空 desc 时不回退为标题或 description', async () => {
    const router = createRouterMock({
      meta: { title: '课程详情' },
    })

    installWxShareSync(router, {
      isEnabled: true,
      resolver: vi.fn(() =>
        Promise.resolve({
          description: '课程详情',
          desc: '',
        })
      ),
    })

    await flushMutationObserver()

    expect(wxMocks.updateAppMessageShareData.mock.lastCall[0].title).toBe('美乐爱觉')
    expect(wxMocks.updateAppMessageShareData.mock.lastCall[0].desc).toBe('')
  })

  it('非 cdn 图片地址保持不变', () => {
    expect(normalizeShareImageUrl('https://example.com/image.png')).toBe(
      'https://example.com/image.png'
    )
  })
})