diff --git a/packages/void/src/cli/cf-version-runner.ts b/packages/void/src/cli/cf-version-runner.ts index f6a887990..c8b8c41be 100644 --- a/packages/void/src/cli/cf-version-runner.ts +++ b/packages/void/src/cli/cf-version-runner.ts @@ -584,16 +584,17 @@ export function createCfVersionRunner(options: { return result; } const version = result.data; - if ( - !record(version) || - version.id !== operation.versionId || - !Array.isArray(version.bindings) - ) { + if (!record(version) || version.id !== operation.versionId) { + return failed('The Cloudflare Worker version was not readable.'); + } + // Cloudflare omits `bindings` for a version that has none. + const bindings = version.bindings === undefined ? [] : version.bindings; + if (!Array.isArray(bindings)) { return failed('The Cloudflare Worker version was not readable.'); } return { ...result, - data: { ...version, resources: { bindings: version.bindings } }, + data: { ...version, bindings, resources: { bindings } }, }; } diff --git a/packages/void/test/unit/cf-version-runner.test.ts b/packages/void/test/unit/cf-version-runner.test.ts index 0e534b39e..e1fb6bfe2 100644 --- a/packages/void/test/unit/cf-version-runner.test.ts +++ b/packages/void/test/unit/cf-version-runner.test.ts @@ -147,6 +147,40 @@ it( REAL_CF_TIMEOUT_MS, ); +it.each([ + { label: 'missing', version: { id: 'version-id', number: 35 }, readable: true }, + { label: 'null', version: { id: 'version-id', number: 35, bindings: null }, readable: false }, + { label: 'an object', version: { id: 'version-id', number: 35, bindings: {} }, readable: false }, +])('reads a version whose bindings are $label', async ({ version, readable }) => { + const prepared = await output(); + try { + const runner = createCfVersionRunner({ + output: prepared, + workerName: 'void-test', + runCf: () => ({ status: 0, stdout: JSON.stringify(version), stderr: '' }), + verifyResources: async () => { + throw new Error('A read must not provision or probe resources'); + }, + }); + const result = await runner( + { type: 'versions.view', versionId: 'version-id', workerName: 'void-test' }, + { capture: true }, + ); + if (readable) { + // Cloudflare omits `bindings` for a version that has none. + expect(result.status).toBe(0); + expect(result.data).toMatchObject({ bindings: [], resources: { bindings: [] } }); + } else { + expect(result).toMatchObject({ + status: 1, + stderr: 'The Cloudflare Worker version was not readable.', + }); + } + } finally { + await prepared.dispose(); + } +}); + it( 'preserves real cf provider codes so a missing Worker can reach its first upload', async () => {