fix(packages): await metadataPayloadBuilder.build() in CreatePackageUseCase#1050
fix(packages): await metadataPayloadBuilder.build() in CreatePackageUseCase#1050ifoche wants to merge 7 commits into
Conversation
…seCase The async build() call was missing `await`, causing a raw Promise object to be stored as package contents instead of the resolved MetadataPackage. This made all module-generated packages appear empty (0 elements on import, empty JSON downloads, no diff data, empty mapping tab). Also removes unnecessary generic type parameters from TransformationRepository to prevent Promise objects from being silently accepted as payload, and adds unit tests for CreatePackageUseCase. Closes: https://app.clickup.com/t/869bvjxj9 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Include the OpenSpec proposal, design, specs, and tasks for the fix-empty-module-package-contents change. Add .claude/ to .gitignore. Also includes prettier formatting applied by pre-commit hook. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BundleMonNo change in files bundle size Groups updated (1)
Final result: ✅ View report in BundleMon website ➡️ |
…le-package-contents # Conflicts: # src/data/tracked-entity-instances/TEID2ApiRepository.ts
…onstructor param Merging development added a userRepository constructor parameter to CreatePackageUseCase, shifting localInstance to the 5th position. The test suite still instantiated the use case with the old 4-arg signature, leaving localInstance undefined and breaking all 5 tests.
xurxodev
left a comment
There was a problem hiding this comment.
thanks @ifoche
This PR fixes a real bug: a missing await on metadataPayloadBuilder.build() in CreatePackageUseCase was storing an unresolved Promise as package contents, makinage empty. The fix itself is correct andminimal. The branch originally also narrowed TransformationRepository.mapPackageTo/mapPackageFrom from generic to a fiMetadataPackage type as an extra safety net a — that part has since been reverted on this branch back to development's fully generic signature, because it broke other legitimate callers once merged with development (see below). What's left to fix ile.
-
Should fix - src/domain/packages/usecases/tests/Creat doubles don't follow the project'sestablished pattern. The rest of the codebase builds test doubles with ts-mockito (mock/when/instance) plus givenA... helper functions that keep construction out osrc/domain/metadata/builders/tests/MetadataPayloadBuilder.spec.tsx, e.g. givenMetadataPayloadBuilderOfCategory). Tnew spec instead hand-rolls every dependency lt inline in beforeEach, and reimplementsStorageClient/DynamicRepositoryFactory collaborators by hand instead of using mock(...)/instance(...). Worth aligning with the existing convention for consistency ng out of sync with how the rest of the suitemocks the same collaborators (DynamicRepositoryFactory, UserRepository, TransformationRepository).
-
Recommendations non blocking
- Worth a short follow-up task to revisit TransformationRepository.mapPackageTo/mapPackageFrom's type safety. The original commit on this branch narrowed the sackage (Input/Output removed) specifically tomake an unresolved Promise a compile-time error — a reasonable goal given this bug's root cause. After merging development into this branch, that narrowing t legitimately pass non-MetadataPackage shapes: DownloadPayloadUseCase/DownloadPayloadFromSyncRuleUseCase (pass SynchronizationPayload, a wider union) and TEID2ApiRepository (passes TrackerPostRequest a bug — by teiTransformations-api.spec.ts,which exercises teiTransformations against DHIS2 wire-format data end-to-end). Reverting to the fully generic signature was the safe choice for this PR's scope, but -leak hole is back open at the type level forany future caller. A follow-up should explore a narrower fix — e.g. a whitelist-style conditional type covering the known valid payload shapes (SynchronizationPayload than touching this again inside an unrelated PR.
…le-package-contents
…convention The tests hand-rolled every collaborator (vi.fn() objects, a real DynamicRepositoryFactory instance) instead of using the mock/when/ instance pattern used elsewhere (e.g. MetadataPayloadBuilder.spec.tsx), and asserted on internal collaborator calls (build()/mapPackageTo() being invoked) rather than on the use case's observable output. Rewrote using ts-mockito with givenA... helpers, and simplified the assertions to what execute() actually persists (package contents, module version) instead of how it gets there -- the collaborator-call checks were redundant with those outcome checks and coupled the test to implementation details.
|
Hi @ifoche, pushed a commit addressing the "Should fix" point from the review:
All 441 tests pass. The non-blocking recommendation about |
Summary
awaitonmetadataPayloadBuilder.build()inCreatePackageUseCase, which caused a raw Promise to be stored as package contents instead of the resolved metadata payload — making all module-generated packages appear emptyTransformationRepository.mapPackageTo/mapPackageFromto prevent Promise objects from being silently accepted as payload (compile-time safety)CreatePackageUseCase(5 test cases)Related Tasks
Test plan
yarn test— all 393 tests pass (48 files)yarn build core-app— builds cleanly🤖 Generated with Claude Code