← back to Wine Finder Next
__tests__/unit/membershipDatabase.test.ts
473 lines
// Unit Tests for Membership Database Operations
import {
bottleDb,
membershipUnitDb,
governanceVoteDb,
marketplaceDb,
sampleUnitDb,
getConfig,
} from '@/lib/membershipDatabase';
import {
createMockBottle,
createMockMembershipUnit,
createMockGovernanceVote,
createMockMarketplaceListing,
} from '../fixtures/testData';
describe('Membership Database', () => {
describe('bottleDb', () => {
it('should create a new bottle', () => {
const bottleData = {
name: 'Test Wine',
vintage: 2010,
producer: 'Test Producer',
region: 'Test Region',
size: '750ml',
totalMembershipUnits: 1000,
availableMembershipUnits: 1000,
estimatedValue: 50000,
provenance: 'Test provenance',
status: 'active' as const,
};
const bottle = bottleDb.create(bottleData);
expect(bottle).toHaveProperty('id');
expect(bottle.id).toMatch(/^bottle_\d+_[a-z0-9]{9}$/);
expect(bottle.name).toBe(bottleData.name);
expect(bottle.vintage).toBe(bottleData.vintage);
expect(bottle).toHaveProperty('createdAt');
expect(bottle).toHaveProperty('updatedAt');
});
it('should get all bottles', () => {
const initialCount = bottleDb.getAll().length;
bottleDb.create({
name: 'Test Wine 1',
vintage: 2010,
producer: 'Test Producer',
region: 'Test Region',
size: '750ml',
totalMembershipUnits: 1000,
availableMembershipUnits: 1000,
estimatedValue: 50000,
provenance: 'Test provenance',
status: 'active' as const,
});
const bottles = bottleDb.getAll();
expect(bottles.length).toBeGreaterThan(initialCount);
});
it('should get bottle by ID', () => {
const bottle = bottleDb.create({
name: 'Test Wine Get',
vintage: 2010,
producer: 'Test Producer',
region: 'Test Region',
size: '750ml',
totalMembershipUnits: 1000,
availableMembershipUnits: 1000,
estimatedValue: 50000,
provenance: 'Test provenance',
status: 'active' as const,
});
const retrieved = bottleDb.getById(bottle.id);
expect(retrieved).toBeDefined();
expect(retrieved?.id).toBe(bottle.id);
expect(retrieved?.name).toBe('Test Wine Get');
});
it('should update a bottle', () => {
const bottle = bottleDb.create({
name: 'Test Wine Update',
vintage: 2010,
producer: 'Test Producer',
region: 'Test Region',
size: '750ml',
totalMembershipUnits: 1000,
availableMembershipUnits: 1000,
estimatedValue: 50000,
provenance: 'Test provenance',
status: 'active' as const,
});
const updated = bottleDb.update(bottle.id, {
status: 'unlocked',
availableMembershipUnits: 500,
});
expect(updated).toBeDefined();
expect(updated?.status).toBe('unlocked');
expect(updated?.availableMembershipUnits).toBe(500);
});
it('should return null when updating non-existent bottle', () => {
const updated = bottleDb.update('bottle_0_nonexist', { status: 'locked' });
expect(updated).toBeNull();
});
});
describe('membershipUnitDb', () => {
it('should create a membership unit', () => {
const unitData = {
bottleId: 'bottle_1700000000000_test12345',
tokenId: 'TEST_TOKEN_1',
ownerId: 'user_1',
ownerEmail: 'test@example.com',
ownerName: 'Test User',
purchasePrice: 10.50,
purchaseDate: new Date(),
status: 'active' as const,
votingPower: 1,
transactionHistory: [],
};
const unit = membershipUnitDb.create(unitData);
expect(unit).toHaveProperty('id');
expect(unit.id).toMatch(/^unit_\d+_[a-z0-9]{9}$/);
expect(unit.ownerId).toBe('user_1');
expect(unit.purchasePrice).toBe(10.50);
});
it('should get units by bottle ID', () => {
const bottleId = 'bottle_1700000000000_testbottle';
membershipUnitDb.create({
bottleId,
tokenId: 'TOKEN_1',
ownerId: 'user_1',
ownerEmail: 'test1@example.com',
ownerName: 'User 1',
purchasePrice: 10,
purchaseDate: new Date(),
status: 'active',
votingPower: 1,
transactionHistory: [],
});
membershipUnitDb.create({
bottleId,
tokenId: 'TOKEN_2',
ownerId: 'user_2',
ownerEmail: 'test2@example.com',
ownerName: 'User 2',
purchasePrice: 10,
purchaseDate: new Date(),
status: 'active',
votingPower: 1,
transactionHistory: [],
});
const units = membershipUnitDb.getByBottleId(bottleId);
expect(units.length).toBeGreaterThanOrEqual(2);
expect(units.every(u => u.bottleId === bottleId)).toBe(true);
});
it('should get units by owner ID', () => {
const ownerId = 'user_testowner';
membershipUnitDb.create({
bottleId: 'bottle_1',
tokenId: 'TOKEN_OWNER_1',
ownerId,
ownerEmail: 'owner@example.com',
ownerName: 'Owner',
purchasePrice: 10,
purchaseDate: new Date(),
status: 'active',
votingPower: 1,
transactionHistory: [],
});
const units = membershipUnitDb.getByOwnerId(ownerId);
expect(units.length).toBeGreaterThanOrEqual(1);
expect(units.every(u => u.ownerId === ownerId)).toBe(true);
});
it('should transfer a membership unit', () => {
const unit = membershipUnitDb.create({
bottleId: 'bottle_1',
tokenId: 'TOKEN_TRANSFER',
ownerId: 'user_1',
ownerEmail: 'user1@example.com',
ownerName: 'User 1',
purchasePrice: 10,
purchaseDate: new Date(),
status: 'active',
votingPower: 1,
transactionHistory: [],
});
const transferred = membershipUnitDb.transfer(
unit.id,
'user_2',
'user2@example.com',
'User 2',
12.50
);
expect(transferred).toBeDefined();
expect(transferred?.ownerId).toBe('user_2');
expect(transferred?.ownerEmail).toBe('user2@example.com');
expect(transferred?.transactionHistory.length).toBe(1);
expect(transferred?.transactionHistory[0].price).toBe(12.50);
});
});
describe('governanceVoteDb', () => {
it('should create a governance vote', () => {
const voteData = {
bottleId: 'bottle_1700000000000_test12345',
proposal: 'Test proposal',
proposalType: 'unlock' as const,
description: 'Test description',
startDate: new Date(),
endDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
status: 'active' as const,
quorumRequired: 50,
approvalThreshold: 66,
createdBy: 'admin',
};
const vote = governanceVoteDb.create(voteData);
expect(vote).toHaveProperty('id');
expect(vote.id).toMatch(/^vote_\d+_[a-z0-9]{9}$/);
expect(vote.votesFor).toBe(0);
expect(vote.votesAgainst).toBe(0);
expect(vote.votesAbstain).toBe(0);
expect(vote.votes).toEqual([]);
});
it('should get active votes', () => {
governanceVoteDb.create({
bottleId: 'bottle_1',
proposal: 'Active proposal',
proposalType: 'unlock',
description: 'Test',
startDate: new Date(Date.now() - 1000),
endDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
status: 'active',
quorumRequired: 50,
approvalThreshold: 66,
createdBy: 'admin',
});
const activeVotes = governanceVoteDb.getActive();
expect(activeVotes.length).toBeGreaterThanOrEqual(1);
expect(activeVotes.every(v => v.status === 'active')).toBe(true);
});
it('should cast a vote', () => {
const bottle = bottleDb.create({
name: 'Test Vote Bottle',
vintage: 2010,
producer: 'Test',
region: 'Test',
size: '750ml',
totalMembershipUnits: 100,
availableMembershipUnits: 100,
estimatedValue: 10000,
provenance: 'Test',
status: 'active',
});
const unit = membershipUnitDb.create({
bottleId: bottle.id,
tokenId: 'TOKEN_VOTE_TEST',
ownerId: 'user_voter',
ownerEmail: 'voter@example.com',
ownerName: 'Voter',
purchasePrice: 100,
purchaseDate: new Date(),
status: 'active',
votingPower: 1,
transactionHistory: [],
});
const vote = governanceVoteDb.create({
bottleId: bottle.id,
proposal: 'Test vote casting',
proposalType: 'unlock',
description: 'Test',
startDate: new Date(),
endDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
status: 'active',
quorumRequired: 50,
approvalThreshold: 66,
createdBy: 'admin',
});
const result = governanceVoteDb.castVote(vote.id, 'user_voter', unit.id, 'for');
expect(result).toBeDefined();
expect(result?.votesFor).toBe(1);
expect(result?.votes.length).toBe(1);
expect(result?.votes[0].choice).toBe('for');
});
it('should prevent double voting', () => {
const bottle = bottleDb.create({
name: 'Test Double Vote Bottle',
vintage: 2010,
producer: 'Test',
region: 'Test',
size: '750ml',
totalMembershipUnits: 100,
availableMembershipUnits: 100,
estimatedValue: 10000,
provenance: 'Test',
status: 'active',
});
const unit = membershipUnitDb.create({
bottleId: bottle.id,
tokenId: 'TOKEN_DOUBLE_VOTE',
ownerId: 'user_double',
ownerEmail: 'double@example.com',
ownerName: 'Double',
purchasePrice: 100,
purchaseDate: new Date(),
status: 'active',
votingPower: 1,
transactionHistory: [],
});
const vote = governanceVoteDb.create({
bottleId: bottle.id,
proposal: 'Test double voting',
proposalType: 'unlock',
description: 'Test',
startDate: new Date(),
endDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
status: 'active',
quorumRequired: 50,
approvalThreshold: 66,
createdBy: 'admin',
});
// First vote should succeed
const firstVote = governanceVoteDb.castVote(vote.id, 'user_double', unit.id, 'for');
expect(firstVote).toBeDefined();
// Second vote should fail
const secondVote = governanceVoteDb.castVote(vote.id, 'user_double', unit.id, 'against');
expect(secondVote).toBeNull();
});
});
describe('marketplaceDb', () => {
it('should create a marketplace listing', () => {
const listingData = {
listingType: 'membership' as const,
itemId: 'unit_1700000000000_test',
bottleId: 'bottle_1700000000000_test',
sellerId: 'user_1',
sellerName: 'Test Seller',
price: 15.50,
currency: 'USD' as const,
status: 'active' as const,
};
const listing = marketplaceDb.create(listingData);
expect(listing).toHaveProperty('id');
expect(listing.id).toMatch(/^listing_\d+_[a-z0-9]{9}$/);
expect(listing.price).toBe(15.50);
expect(listing).toHaveProperty('listedAt');
});
it('should get active listings', () => {
marketplaceDb.create({
listingType: 'membership',
itemId: 'unit_active',
bottleId: 'bottle_1',
sellerId: 'user_1',
sellerName: 'Seller',
price: 10,
currency: 'USD',
status: 'active',
});
const activeListings = marketplaceDb.getActive();
expect(activeListings.length).toBeGreaterThanOrEqual(1);
expect(activeListings.every(l => l.status === 'active')).toBe(true);
});
it('should complete a sale', () => {
const unit = membershipUnitDb.create({
bottleId: 'bottle_sale',
tokenId: 'TOKEN_SALE',
ownerId: 'user_seller',
ownerEmail: 'seller@example.com',
ownerName: 'Seller',
purchasePrice: 10,
purchaseDate: new Date(),
status: 'active',
votingPower: 1,
transactionHistory: [],
});
const listing = marketplaceDb.create({
listingType: 'membership',
itemId: unit.id,
bottleId: 'bottle_sale',
sellerId: 'user_seller',
sellerName: 'Seller',
price: 12,
currency: 'USD',
status: 'active',
});
const completed = marketplaceDb.completeSale(
listing.id,
'user_buyer',
'buyer@example.com',
'Buyer'
);
expect(completed).toBeDefined();
expect(completed?.status).toBe('sold');
expect(completed?.soldTo).toBe('user_buyer');
expect(completed).toHaveProperty('soldAt');
// Verify ownership transfer
const transferredUnit = membershipUnitDb.getById(unit.id);
expect(transferredUnit?.ownerId).toBe('user_buyer');
});
it('should cancel a listing', () => {
const listing = marketplaceDb.create({
listingType: 'membership',
itemId: 'unit_cancel',
bottleId: 'bottle_1',
sellerId: 'user_1',
sellerName: 'Seller',
price: 10,
currency: 'USD',
status: 'active',
});
const cancelled = marketplaceDb.cancel(listing.id);
expect(cancelled).toBeDefined();
expect(cancelled?.status).toBe('cancelled');
});
});
describe('Platform Configuration', () => {
it('should get platform config', () => {
const config = getConfig();
expect(config).toHaveProperty('votingQuorumPercentage');
expect(config).toHaveProperty('votingApprovalThreshold');
expect(config).toHaveProperty('platformFeePercentage');
expect(typeof config.votingQuorumPercentage).toBe('number');
});
});
});