Restructure background update checker tests

Collapse duplicate no-op scenarios into a state table and assert user-visible update outcomes instead of narrow call plumbing.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-03-11 16:08:01 +09:00
parent 55aa1c0054
commit 09a3c54f85
@@ -51,11 +51,21 @@ mock.module("../../../shared/logger", () => ({ log: () => {} }))
const modulePath = "./background-update-check?test" const modulePath = "./background-update-check?test"
const { runBackgroundUpdateCheck } = await import(modulePath) const { runBackgroundUpdateCheck } = await import(modulePath)
describe("runBackgroundUpdateCheck", () => { async function runCheck(autoUpdate = true): Promise<void> {
const mockCtx = { directory: "/test" } as PluginInput const mockContext = { directory: "/test" } as PluginInput
const getToastMessage: ToastMessageGetter = (isUpdate, version) => const getToastMessage: ToastMessageGetter = (isUpdate, version) =>
isUpdate ? `Update to ${version}` : "Up to date" isUpdate ? `Update to ${version}` : "Up to date"
await runBackgroundUpdateCheck(mockContext, autoUpdate, getToastMessage)
}
function expectNoUpdateEffects(): void {
expect(mockShowUpdateAvailableToast).not.toHaveBeenCalled()
expect(mockShowAutoUpdatedToast).not.toHaveBeenCalled()
expect(mockRunBunInstall).not.toHaveBeenCalled()
}
describe("runBackgroundUpdateCheck", () => {
beforeEach(() => { beforeEach(() => {
mockFindPluginEntry.mockReset() mockFindPluginEntry.mockReset()
mockGetCachedVersion.mockReset() mockGetCachedVersion.mockReset()
@@ -73,61 +83,42 @@ describe("runBackgroundUpdateCheck", () => {
mockRunBunInstall.mockResolvedValue(true) mockRunBunInstall.mockResolvedValue(true)
}) })
describe("#given no plugin entry found", () => { describe("#given no-op scenarios", () => {
it("returns early without showing any toast", async () => { it.each([
{
name: "plugin entry is missing",
setup: () => {
mockFindPluginEntry.mockReturnValue(null)
},
},
{
name: "no cached or pinned version exists",
setup: () => {
mockFindPluginEntry.mockReturnValue(createPluginEntry({ entry: "oh-my-opencode" }))
mockGetCachedVersion.mockReturnValue(null)
},
},
{
name: "latest version lookup fails",
setup: () => {
mockGetLatestVersion.mockResolvedValue(null)
},
},
{
name: "current version is already latest",
setup: () => {
mockGetLatestVersion.mockResolvedValue("3.4.0")
},
},
])("returns without user-visible update effects when $name", async ({ setup }) => {
//#given //#given
mockFindPluginEntry.mockReturnValue(null) setup()
//#when
await runBackgroundUpdateCheck(mockCtx, true, getToastMessage)
//#then
expect(mockFindPluginEntry).toHaveBeenCalledTimes(1)
expect(mockShowUpdateAvailableToast).not.toHaveBeenCalled()
expect(mockShowAutoUpdatedToast).not.toHaveBeenCalled()
expect(mockRunBunInstall).not.toHaveBeenCalled()
})
})
describe("#given no version available", () => {
it("returns early when neither cached nor pinned version exists", async () => {
//#given
mockFindPluginEntry.mockReturnValue(createPluginEntry({ entry: "oh-my-opencode" }))
mockGetCachedVersion.mockReturnValue(null)
//#when //#when
await runBackgroundUpdateCheck(mockCtx, true, getToastMessage) await runCheck()
//#then
expect(mockGetCachedVersion).toHaveBeenCalledTimes(1)
expect(mockGetLatestVersion).not.toHaveBeenCalled()
expect(mockShowUpdateAvailableToast).not.toHaveBeenCalled()
expect(mockShowAutoUpdatedToast).not.toHaveBeenCalled()
})
})
describe("#given latest version fetch fails", () => {
it("returns early without toasts", async () => {
//#given
mockGetLatestVersion.mockResolvedValue(null)
//#when
await runBackgroundUpdateCheck(mockCtx, true, getToastMessage)
//#then //#then
expect(mockGetLatestVersion).toHaveBeenCalledWith("latest") expectNoUpdateEffects()
expect(mockRunBunInstall).not.toHaveBeenCalled()
expect(mockShowUpdateAvailableToast).not.toHaveBeenCalled()
expect(mockShowAutoUpdatedToast).not.toHaveBeenCalled()
})
})
describe("#given already on latest version", () => {
it("returns early without any action", async () => {
//#given
mockGetCachedVersion.mockReturnValue("3.4.0")
mockGetLatestVersion.mockResolvedValue("3.4.0")
//#when
await runBackgroundUpdateCheck(mockCtx, true, getToastMessage)
//#then
expect(mockGetLatestVersion).toHaveBeenCalledTimes(1)
expect(mockRunBunInstall).not.toHaveBeenCalled()
expect(mockShowUpdateAvailableToast).not.toHaveBeenCalled()
expect(mockShowAutoUpdatedToast).not.toHaveBeenCalled()
}) })
}) })
@@ -136,9 +127,13 @@ describe("runBackgroundUpdateCheck", () => {
//#given //#given
const autoUpdate = false const autoUpdate = false
//#when //#when
await runBackgroundUpdateCheck(mockCtx, autoUpdate, getToastMessage) await runCheck(autoUpdate)
//#then //#then
expect(mockShowUpdateAvailableToast).toHaveBeenCalledWith(mockCtx, "3.5.0", getToastMessage) expect(mockShowUpdateAvailableToast).toHaveBeenCalledWith(
expect.objectContaining({ directory: "/test" }),
"3.5.0",
expect.any(Function)
)
expect(mockRunBunInstall).not.toHaveBeenCalled() expect(mockRunBunInstall).not.toHaveBeenCalled()
expect(mockShowAutoUpdatedToast).not.toHaveBeenCalled() expect(mockShowAutoUpdatedToast).not.toHaveBeenCalled()
}) })
@@ -149,7 +144,7 @@ describe("runBackgroundUpdateCheck", () => {
//#given //#given
mockFindPluginEntry.mockReturnValue(createPluginEntry({ isPinned: true, pinnedVersion: "3.4.0" })) mockFindPluginEntry.mockReturnValue(createPluginEntry({ isPinned: true, pinnedVersion: "3.4.0" }))
//#when //#when
await runBackgroundUpdateCheck(mockCtx, true, getToastMessage) await runCheck()
//#then //#then
expect(mockShowUpdateAvailableToast).toHaveBeenCalledTimes(1) expect(mockShowUpdateAvailableToast).toHaveBeenCalledTimes(1)
expect(mockRunBunInstall).not.toHaveBeenCalled() expect(mockRunBunInstall).not.toHaveBeenCalled()
@@ -166,7 +161,7 @@ describe("runBackgroundUpdateCheck", () => {
} }
) )
//#when //#when
await runBackgroundUpdateCheck(mockCtx, true, getToastMessage) await runCheck()
//#then //#then
expect(mockShowUpdateAvailableToast).toHaveBeenCalledTimes(1) expect(mockShowUpdateAvailableToast).toHaveBeenCalledTimes(1)
expect(capturedToastMessage).toBeDefined() expect(capturedToastMessage).toBeDefined()
@@ -184,11 +179,15 @@ describe("runBackgroundUpdateCheck", () => {
//#given //#given
mockRunBunInstall.mockResolvedValue(true) mockRunBunInstall.mockResolvedValue(true)
//#when //#when
await runBackgroundUpdateCheck(mockCtx, true, getToastMessage) await runCheck()
//#then //#then
expect(mockInvalidatePackage).toHaveBeenCalledTimes(1) expect(mockInvalidatePackage).toHaveBeenCalledTimes(1)
expect(mockRunBunInstall).toHaveBeenCalledTimes(1) expect(mockRunBunInstall).toHaveBeenCalledTimes(1)
expect(mockShowAutoUpdatedToast).toHaveBeenCalledWith(mockCtx, "3.4.0", "3.5.0") expect(mockShowAutoUpdatedToast).toHaveBeenCalledWith(
expect.objectContaining({ directory: "/test" }),
"3.4.0",
"3.5.0"
)
expect(mockShowUpdateAvailableToast).not.toHaveBeenCalled() expect(mockShowUpdateAvailableToast).not.toHaveBeenCalled()
}) })
}) })
@@ -198,10 +197,14 @@ describe("runBackgroundUpdateCheck", () => {
//#given //#given
mockRunBunInstall.mockResolvedValue(false) mockRunBunInstall.mockResolvedValue(false)
//#when //#when
await runBackgroundUpdateCheck(mockCtx, true, getToastMessage) await runCheck()
//#then //#then
expect(mockRunBunInstall).toHaveBeenCalledTimes(1) expect(mockRunBunInstall).toHaveBeenCalledTimes(1)
expect(mockShowUpdateAvailableToast).toHaveBeenCalledWith(mockCtx, "3.5.0", getToastMessage) expect(mockShowUpdateAvailableToast).toHaveBeenCalledWith(
expect.objectContaining({ directory: "/test" }),
"3.5.0",
expect.any(Function)
)
expect(mockShowAutoUpdatedToast).not.toHaveBeenCalled() expect(mockShowAutoUpdatedToast).not.toHaveBeenCalled()
}) })
}) })