🎯 Objective
Implement a complete test suite for the Promotion NFT Contract built with OpenZeppelin’s Stellar contracts, ensuring that minting, redemption, transfer, access control, and event emission work as expected for non-fungible promotional NFTs (e.g., discount codes, access passes).
🧪 Scope
Test the following modules and behaviors:
promotion-nft-contract/src/
mint.rs // One-off NFT minting with metadata
redeem.rs // Redemption flow (mark as used)
transfer.rs // Ownership transfers
roles.rs // Role-based access control
metadata.rs // Token-specific metadata access
storage.rs // NFT ownership, state, redemption tracking
lib.rs // Contract entry and initialization
✅ Test Categories & Cases
1. Initialization
- ✅ Only one call to
initialize() allowed
- ✅
DEFAULT_ADMIN_ROLE correctly set
- ✅ Revert on second initialization
- ✅ Emit
ContractInitialized only once
2. Role Management
- ✅ Only
ADMIN_ROLE can grant MINTER_ROLE
- ✅ Only
REDEEMER_ROLE (if used) can redeem on behalf of users
- ✅ Revert on unauthorized role access
- ✅ Events:
RoleGranted, RoleRevoked
3. Minting Logic
- ✅ Only minters can mint (
mint_promo(recipient, metadata_uri))
- ✅ Revert on unauthorized mint
- ✅ Revert if recipient is invalid
- ✅ Token ID must be unique
- ✅ Metadata URI stored and retrievable
- ✅ Emit
PromoMinted(token_id, recipient)
4. Redemption Logic
- ✅ User can redeem if they own the token
- ✅ Optional: allow redemption by
REDEEMER_ROLE
- ✅ Cannot redeem the same token twice
- ✅ Mark token as redeemed in storage
- ✅ Emit
Redeemed(token_id, user, timestamp)
- ✅ Prevent transfers after redemption (if enforced)
5. Transfer Logic
- ✅ Owner can transfer to another valid address
- ✅ Ownership updates after transfer
- ✅ Revert if non-owner tries to transfer
- ✅ Emit
Transfer(from, to, token_id)
- ✅ Optional: disallow transfer after redemption
6. Metadata Access
- ✅ Metadata URI must match what was minted
- ✅ Immutable after mint
- ✅ Test uniqueness of metadata per token
- ✅ Query metadata by
token_id
7. Storage Integrity
- ✅ Ensure token IDs are never duplicated
- ✅ Validate redemption status is persisted
- ✅ No overwrites of metadata or ownership
- ✅ All keys follow expected isolation pattern
8. Event Emission
🧰 Tooling & Environment
-
Use soroban-sdk test helpers and mocks
-
Organize tests into modules by feature: mint_tests, redeem_tests, transfer_tests, roles_tests
-
Use representative mock accounts:
admin, seller, buyer1, redeemer
📌 Additional Recommendations
- Cover edge cases (mint same token twice, redeem twice, transfer after redemption)
- Use mock timestamps to test redemption timing (optional)
- Prepare for future extension to burn-on-redeem logic
- Structure test assertions for easy CI logging
🔗 References
🎯 Objective
Implement a complete test suite for the Promotion NFT Contract built with OpenZeppelin’s Stellar contracts, ensuring that minting, redemption, transfer, access control, and event emission work as expected for non-fungible promotional NFTs (e.g., discount codes, access passes).
🧪 Scope
Test the following modules and behaviors:
✅ Test Categories & Cases
1. Initialization
initialize()allowedDEFAULT_ADMIN_ROLEcorrectly setContractInitializedonly once2. Role Management
ADMIN_ROLEcan grantMINTER_ROLEREDEEMER_ROLE(if used) can redeem on behalf of usersRoleGranted,RoleRevoked3. Minting Logic
mint_promo(recipient, metadata_uri))PromoMinted(token_id, recipient)4. Redemption Logic
REDEEMER_ROLERedeemed(token_id, user, timestamp)5. Transfer Logic
Transfer(from, to, token_id)6. Metadata Access
token_id7. Storage Integrity
8. Event Emission
✅ Verify all relevant events:
ContractInitializedPromoMintedRedeemedTransferRoleGranted,RoleRevoked✅ Event values should be correct and consistent
🧰 Tooling & Environment
Use
soroban-sdktest helpers and mocksOrganize tests into modules by feature:
mint_tests,redeem_tests,transfer_tests,roles_testsUse representative mock accounts:
admin,seller,buyer1,redeemer📌 Additional Recommendations
🔗 References