import sinon, { SinonStub } from 'sinon'; import * as publishExports from '../publish'; import * as readAuthAndConfigExports from '../../helpers/read-auth-and-config'; import * as fetchProductModuleDefinitionExports from '../../helpers/fetch-product-module-definition'; import * as publishProductModuleHelperExports from '../../helpers/publish-product-module'; import * as rootApiExports from '../../helpers/root-api'; import { rootConfigFileExample } from '../../../test-utils/test-root-funeral-pm'; import { expect } from '../../../test-utils'; import { CLIError, ExitCodes, PlatformError } from '../../errors/platform-error'; describe('rp publish', function () { const sandbox = sinon.createSandbox(); let fetchDefinitionStub: SinonStub; let publishDraftStub: SinonStub; beforeEach(function () { sandbox.stub(readAuthAndConfigExports, 'readAuthAndConfig').returns({ apiKey: 'test_api_key', config: rootConfigFileExample, }); fetchDefinitionStub = sandbox.stub(fetchProductModuleDefinitionExports, 'fetchProductModuleDefinition'); publishDraftStub = sandbox.stub(publishProductModuleHelperExports, 'publishLatestProductModuleDraftDefinition'); }); afterEach(function () { sandbox.verifyAndRestore(); }); const notFoundError = (message: string) => new PlatformError({ error: { message, type: 'not_found_error', more_info: '' } }, 404); it('fails with a friendly CLIError before publishing when there is no draft definition', async function () { fetchDefinitionStub.rejects(notFoundError("Product module definition with ID of 'undefined' not found")); let thrown: unknown; try { await publishExports.publish({ force: true }); } catch (error) { thrown = error; } expect(thrown).to.be.instanceOf(CLIError); expect((thrown as CLIError).exitCode).to.equal(ExitCodes.GENERAL_ERROR); expect((thrown as CLIError).message).to.contain("No draft definition found for product module 'root_funeral'"); expect((thrown as CLIError).message).to.contain('rp push'); sandbox.assert.notCalled(publishDraftStub); }); it('rethrows a missing-module 404 unchanged', async function () { const moduleNotFound = notFoundError("Product module with key 'root_funeral' not found"); fetchDefinitionStub.rejects(moduleNotFound); let thrown: unknown; try { await publishExports.publish({ force: true }); } catch (error) { thrown = error; } expect(thrown).to.equal(moduleNotFound); sandbox.assert.notCalled(publishDraftStub); }); it('publishes the draft when the pre-publish fetch succeeds', async function () { fetchDefinitionStub.onFirstCall().resolves({ version: '2.227.0' }); // Post-publish parallel fetches of the new live and draft versions. fetchDefinitionStub.onSecondCall().resolves({ version: '3.0.0' }); fetchDefinitionStub.onThirdCall().resolves({ version: '3.1.0' }); publishDraftStub.resolves(); sandbox.stub(rootApiExports, 'getNewApiHelper').returns({ send: sandbox.stub().resolves({ product_module_id: 'pm_id', organization_id: rootConfigFileExample.organizationId, owned_by_organization_id: rootConfigFileExample.organizationId, sandbox: true, live: true, draft_id: 'draft_id', live_id: 'live_id', restricted: false, key: rootConfigFileExample.productModuleKey, name: rootConfigFileExample.productModuleName, created_at: '2026-01-01T00:00:00.000Z', created_by: { id: 'user_id', type: 'user' }, }), } as unknown as rootApiExports.RootAPIHelper); await publishExports.publish({ force: true }); sandbox.assert.calledOnce(publishDraftStub); sandbox.assert.calledThrice(fetchDefinitionStub); }); });