plugin-manager.spec.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import { readFileSync } from 'node:fs'
  2. import { runInContext } from 'node:vm'
  3. import { JSDOM } from 'jsdom'
  4. import { expect, it, vi } from 'vitest'
  5. import { resolveDesktopLocale } from '../src/locale.ts'
  6. it('keeps disabled packages visible without an in-page recovery panel', async () => {
  7. const dom = new JSDOM(readFileSync(new URL('../renderer/plugin-manager.html', import.meta.url), 'utf8'), { runScripts: 'outside-only' })
  8. let enabled = false
  9. const toggle = vi.fn(async (_name: string, active: boolean) => { enabled = active })
  10. const api = {
  11. locale: async () => resolveDesktopLocale('en'),
  12. plugins: { list: async () => [{ name: 'example-plugin', version: '1.0.0', enabled }], toggle },
  13. }
  14. Object.defineProperty(dom.window, 'dshDesktop', { value: api })
  15. try {
  16. runInContext(readFileSync(new URL('../renderer/plugin-manager.js', import.meta.url), 'utf8'), dom.getInternalVMContext())
  17. const document = dom.window.document
  18. await expect.poll(() => document.querySelector('#plugins li')?.textContent).toContain('example-plugin')
  19. expect(document.querySelector('#recovery')).toBeNull()
  20. expect(document.querySelector('#plugins li')?.textContent).toMatchInlineSnapshot('"example-plugin1.0.0 · DisabledEnableUpdateRemove"')
  21. document.querySelector<HTMLButtonElement>('#plugins li button')?.click()
  22. await expect.poll(() => toggle.mock.calls).toEqual([['example-plugin', true]])
  23. await expect.poll(() => document.querySelector('#plugins li')?.textContent).toBe('example-plugin1.0.0DisableUpdateRemove')
  24. } finally { dom.window.close() }
  25. })
  26. it.each(['en', 'zh-CN'])('updates through the inline form, including the installed version (%s)', async (language) => {
  27. const dom = new JSDOM(readFileSync(new URL('../renderer/plugin-manager.html', import.meta.url), 'utf8'), { runScripts: 'outside-only' })
  28. const locale = resolveDesktopLocale(language)
  29. const update = vi.fn(async () => {})
  30. Object.defineProperty(dom.window, 'dshDesktop', { value: {
  31. locale: async () => locale,
  32. plugins: { list: async () => [{ name: 'example-plugin', version: '1.0.0', enabled: true }], update },
  33. } })
  34. try {
  35. runInContext(readFileSync(new URL('../renderer/plugin-manager.js', import.meta.url), 'utf8'), dom.getInternalVMContext())
  36. const document = dom.window.document
  37. await expect.poll(() => document.querySelector('#plugins li')?.textContent).toContain('example-plugin')
  38. const updateButton = () => document.querySelectorAll<HTMLButtonElement>('#plugins li button')[1]!
  39. const form = document.querySelector<HTMLFormElement>('#update-form')!
  40. const version = document.querySelector<HTMLInputElement>('#update-version')!
  41. updateButton().click()
  42. expect(form.hidden).toBe(false)
  43. expect(version.value).toBe('1.0.0')
  44. expect(document.activeElement).toBe(version)
  45. expect(document.querySelector('#update-label')?.textContent).toBe(locale.messages.targetVersion.replace('{name}', 'example-plugin'))
  46. expect(document.querySelector('#update-cancel')?.textContent).toBe(locale.messages.cancel)
  47. if (language === 'en') {
  48. expect({ label: document.querySelector('#update-label')?.textContent,
  49. actions: [...form.querySelectorAll('button')].map(button => button.textContent) }).toMatchInlineSnapshot(`
  50. {
  51. "actions": [
  52. "Update",
  53. "Cancel",
  54. ],
  55. "label": "Enter the target version for example-plugin",
  56. }
  57. `)
  58. }
  59. document.querySelector<HTMLButtonElement>('#update-cancel')!.click()
  60. expect(form.hidden).toBe(true)
  61. expect(document.activeElement).toBe(updateButton())
  62. expect(update).not.toHaveBeenCalled()
  63. for (const target of ['1.0.0', '^2.0.0']) {
  64. updateButton().click()
  65. version.value = target
  66. form.requestSubmit()
  67. await expect.poll(() => document.querySelector('#status')?.textContent).toBe(locale.messages.operationComplete)
  68. expect(update).toHaveBeenLastCalledWith('example-plugin', target)
  69. expect(form.hidden).toBe(true)
  70. }
  71. expect(update).toHaveBeenCalledTimes(2)
  72. } finally { dom.window.close() }
  73. })