Implements support for both individual persons and organizations as members. Changes: - Added MemberType enum (INDIVIDUAL, ORGANIZATION) to distinguish member types - Added member_type column to database (defaults to INDIVIDUAL for backward compatibility) - Added company_name field for organizations - Made first_name nullable (required for individuals, optional for organizations) - Implemented conditional validation: - INDIVIDUAL members require first_name - ORGANIZATION members require company_name - Updated GraphQL schema with new memberType and companyName fields - Updated all resolvers to handle new fields and validation - Added comprehensive unit tests for validation logic - Updated existing tests to work with new fields - All 53 tests passing Technical notes: - Using memberType instead of 'kind' to avoid GraphQL introspection conflicts - Using native_enum=False for SQLite compatibility - Using batch_alter_table for SQLite ALTER COLUMN compatibility - Backward compatible: existing members automatically become INDIVIDUAL type 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
85 lines
3.0 KiB
Python
85 lines
3.0 KiB
Python
"""Integration tests for Member database model."""
|
|
|
|
from datetime import datetime
|
|
|
|
import pytest
|
|
|
|
from src.models.member import Member
|
|
|
|
|
|
class TestMemberModel:
|
|
"""Tests for Member SQLAlchemy model."""
|
|
|
|
async def test_create_member_with_minimal_data(self, async_session):
|
|
"""Test creating a member with only firstName (minimal required data)."""
|
|
member = Member(first_name="Alice")
|
|
async_session.add(member)
|
|
await async_session.commit()
|
|
await async_session.refresh(member)
|
|
|
|
assert member.id is not None
|
|
assert member.first_name == "Alice"
|
|
assert member.last_name is None
|
|
assert member.street is None
|
|
assert member.apartment_number is None
|
|
assert member.zip is None
|
|
assert member.city is None
|
|
assert member.country is None
|
|
assert member.email is None
|
|
assert member.phone is None
|
|
assert isinstance(member.created_at, datetime)
|
|
assert isinstance(member.updated_at, datetime)
|
|
|
|
async def test_create_member_with_complete_data(self, async_session):
|
|
"""Test creating a member with all fields populated."""
|
|
member = Member(
|
|
first_name="Bob",
|
|
last_name="Johnson",
|
|
street="123 Main St",
|
|
apartment_number="4B",
|
|
zip="12345",
|
|
city="Springfield",
|
|
country="USA",
|
|
email="bob@example.com",
|
|
phone="+14155551234",
|
|
)
|
|
async_session.add(member)
|
|
await async_session.commit()
|
|
await async_session.refresh(member)
|
|
|
|
assert member.id is not None
|
|
assert member.first_name == "Bob"
|
|
assert member.last_name == "Johnson"
|
|
assert member.street == "123 Main St"
|
|
assert member.apartment_number == "4B"
|
|
assert member.zip == "12345"
|
|
assert member.city == "Springfield"
|
|
assert member.country == "USA"
|
|
assert member.email == "bob@example.com"
|
|
assert member.phone == "+14155551234"
|
|
|
|
async def test_member_timestamps(self, async_session):
|
|
"""Test that created_at and updated_at are set correctly."""
|
|
member = Member(first_name="Charlie")
|
|
async_session.add(member)
|
|
await async_session.commit()
|
|
await async_session.refresh(member)
|
|
|
|
assert isinstance(member.created_at, datetime)
|
|
assert isinstance(member.updated_at, datetime)
|
|
# For new members, created_at should equal updated_at
|
|
assert member.created_at == member.updated_at
|
|
|
|
async def test_member_repr(self, async_session):
|
|
"""Test the __repr__ method of Member."""
|
|
member = Member(first_name="David", last_name="Smith")
|
|
async_session.add(member)
|
|
await async_session.commit()
|
|
await async_session.refresh(member)
|
|
|
|
repr_str = repr(member)
|
|
assert "Member" in repr_str
|
|
assert f"id={member.id}" in repr_str
|
|
assert "type=INDIVIDUAL" in repr_str
|
|
assert "name='David Smith'" in repr_str
|