UNPKG

@budibase/server

Version:
225 lines (183 loc) • 6.56 kB
import tk from "timekeeper" import * as setup from "../../../api/routes/tests/utilities" import { processMigrations } from "../../migrationsProcessor" import migration from "../20250729134531_workspace_cleanups" import { AppMigration, updateAppMigrationMetadata } from "../.." import sdk from "../../../sdk" import { structures } from "@budibase/backend-core/tests" import { db } from "@budibase/backend-core" import { basicScreen } from "../../../tests/utilities/structures" import { WorkspaceApp } from "@budibase/types" const MIGRATIONS: AppMigration[] = [ { id: "20250729134531_workspace_cleanups", func: jest.fn().mockImplementation(migration), disabled: false, }, ] const config = setup.getConfig() async function createWorkspaceApp(isDefault = false) { const workspaceApp = await sdk.workspaceApps.create( structures.workspaceApps.workspaceApp({ isDefault }) ) return workspaceApp } describe.each([ ["dev", () => config.getAppId()], ["prod", () => config.getProdAppId()], ])("Workspace cleanups migration (%s)", (_, getAppId) => { let defaultWorkspaceApp: WorkspaceApp beforeAll(async () => { await config.init() }) beforeEach(async () => { await config.newTenant() for (const appId of [config.getAppId(), config.getProdAppId()]) { await config.doInContext(appId, async () => { await updateAppMigrationMetadata({ appId, version: "", }) }) const workspaceApps = await config.doInContext( getAppId(), sdk.workspaceApps.fetch ) expect(workspaceApps).toHaveLength(1) defaultWorkspaceApp = workspaceApps[0] } tk.freeze(structures.generator.date()) jest.clearAllMocks() }) afterEach(() => { expect(MIGRATIONS[0].func).toHaveBeenCalledTimes(2) }) it("does nothing when only one default workspace app exists", async () => { await config.doInContext(getAppId(), () => processMigrations(config.getAppId(), MIGRATIONS) ) const workspaceApps = await config.doInContext( getAppId(), sdk.workspaceApps.fetch ) expect(workspaceApps).toHaveLength(1) expect(workspaceApps[0].isDefault).toBe(true) }) it("does nothing when multiple non-default workspace apps exist", async () => { await config.doInContext(getAppId(), async () => { await createWorkspaceApp(false) await createWorkspaceApp(false) }) await config.doInContext(getAppId(), () => processMigrations(config.getAppId(), MIGRATIONS) ) const workspaceApps = await config.doInContext( getAppId(), sdk.workspaceApps.fetch ) expect(workspaceApps).toHaveLength(3) }) it("removes duplicate default workspace apps and keeps only one", async () => { await config.doInContext(getAppId(), async () => { await createWorkspaceApp(true) await createWorkspaceApp(true) await createWorkspaceApp(true) }) await config.doInContext(getAppId(), () => processMigrations(config.getAppId(), MIGRATIONS) ) const workspaceApps = await config.doInContext( getAppId(), sdk.workspaceApps.fetch ) expect(workspaceApps).toHaveLength(1) expect(workspaceApps[0].isDefault).toBe(true) }) it("updates screens to reference the kept workspace app when removing duplicates", async () => { let keptWorkspaceAppId: string = undefined! await config.doInContext(getAppId(), async () => { const workspaceApp1 = await createWorkspaceApp(true) const workspaceApp2 = await createWorkspaceApp(true) tk.travel(Date.now() + 1000) await sdk.workspaceApps.update(workspaceApp1) const toDelete1 = defaultWorkspaceApp._id! const toDelete2 = workspaceApp2._id! keptWorkspaceAppId = workspaceApp1._id! // Create screens that reference both workspace apps await sdk.screens.create({ ...basicScreen(), workspaceAppId: toDelete1, }) await sdk.screens.create({ ...basicScreen(), workspaceAppId: toDelete2, }) await sdk.screens.create({ ...basicScreen(), workspaceAppId: toDelete1, }) }) await config.doInContext(getAppId(), () => processMigrations(config.getAppId(), MIGRATIONS) ) const workspaceApps = await config.doInContext( getAppId(), sdk.workspaceApps.fetch ) const screens = await config.doInContext(getAppId(), sdk.screens.fetch) expect(workspaceApps).toHaveLength(1) expect(workspaceApps[0]._id).toBe(keptWorkspaceAppId) // All screens should now reference the kept workspace app const screensWithWorkspaceAppId = screens.filter(s => s.workspaceAppId) expect(screensWithWorkspaceAppId).toHaveLength(4) screensWithWorkspaceAppId.forEach(screen => { expect(screen.workspaceAppId).toBe(keptWorkspaceAppId) }) }) it("handles mixed default and non-default workspace apps correctly", async () => { await config.doInContext(getAppId(), async () => { await createWorkspaceApp(true) await createWorkspaceApp(true) await createWorkspaceApp(false) }) await config.doInContext(getAppId(), () => processMigrations(config.getAppId(), MIGRATIONS) ) const workspaceApps = await config.doInContext( getAppId(), sdk.workspaceApps.fetch ) expect(workspaceApps).toHaveLength(2) const defaultApps = workspaceApps.filter(app => app.isDefault) const nonDefaultApps = workspaceApps.filter(app => !app.isDefault) expect(defaultApps).toHaveLength(1) expect(nonDefaultApps).toHaveLength(1) }) it("handles different workspace apps between dev and prod", async () => { const prodAppId = db.getProdAppID(getAppId()) const devAppId = db.getDevAppID(getAppId()) await config.doInContext(prodAppId, async () => { await createWorkspaceApp(true) }) await config.doInContext(devAppId, async () => { await createWorkspaceApp(true) }) expect( await config.doInContext(prodAppId, async () => (await sdk.workspaceApps.fetch()).map(a => a._id) ) ).not.toEqual( await config.doInContext(devAppId, async () => (await sdk.workspaceApps.fetch()).map(a => a._id) ) ) await config.doInContext(getAppId(), () => processMigrations(config.getAppId(), MIGRATIONS) ) const workspaceApps = await config.doInContext( getAppId(), sdk.workspaceApps.fetch ) expect(workspaceApps).toHaveLength(1) }) })