"""End-to-end tests for GraphQL API over HTTP.""" import pytest class TestGraphQLAPI: """E2E tests for complete GraphQL request/response flows.""" async def test_query_members_via_http(self, graphql_client): """Test complete query flow via HTTP POST to /graphql.""" # First create some test data create_query = """ mutation { createMember(input: {firstName: "Alice", lastName: "Smith"}) { id } } """ await graphql_client.post("/graphql", json={"query": create_query}) # Query members via HTTP query = """ query { members { id firstName lastName } } """ response = await graphql_client.post("/graphql", json={"query": query}) assert response.status_code == 200 data = response.json() assert "data" in data assert "members" in data["data"] assert len(data["data"]["members"]) == 1 assert data["data"]["members"][0]["firstName"] == "Alice" assert data["data"]["members"][0]["lastName"] == "Smith" async def test_create_member_mutation_via_http(self, graphql_client): """Test complete mutation flow via HTTP POST to /graphql.""" mutation = """ mutation { createMember(input: { firstName: "Bob" lastName: "Johnson" email: "bob@example.com" }) { id firstName lastName email } } """ response = await graphql_client.post("/graphql", json={"query": mutation}) assert response.status_code == 200 data = response.json() assert "data" in data assert "createMember" in data["data"] member = data["data"]["createMember"] assert member["firstName"] == "Bob" assert member["lastName"] == "Johnson" assert member["email"] == "bob@example.com" assert member["id"] is not None async def test_graphql_introspection_schema(self, graphql_client): """Test GraphQL introspection query for __schema.""" query = """ query { __schema { queryType { name } mutationType { name } types { name kind } } } """ response = await graphql_client.post("/graphql", json={"query": query}) assert response.status_code == 200 data = response.json() assert "data" in data assert "__schema" in data["data"] schema = data["data"]["__schema"] assert schema["queryType"]["name"] == "Query" assert schema["mutationType"]["name"] == "Mutation" # Check that Member type exists type_names = [t["name"] for t in schema["types"]] assert "Member" in type_names async def test_graphql_introspection_type(self, graphql_client): """Test GraphQL introspection query for __type.""" query = """ query { __type(name: "Member") { name kind fields { name type { name kind } } } } """ response = await graphql_client.post("/graphql", json={"query": query}) assert response.status_code == 200 data = response.json() assert "data" in data assert "__type" in data["data"] member_type = data["data"]["__type"] assert member_type["name"] == "Member" assert member_type["kind"] == "OBJECT" # Check that expected fields exist field_names = [f["name"] for f in member_type["fields"]] assert "id" in field_names assert "firstName" in field_names assert "lastName" in field_names assert "email" in field_names async def test_validation_error_returns_400(self, graphql_client): """Test that validation errors return proper error response.""" mutation = """ mutation { createMember(input: { firstName: "Charlie" email: "invalid-email" }) { id } } """ response = await graphql_client.post("/graphql", json={"query": mutation}) # GraphQL typically returns 200 even with errors, but errors are in response assert response.status_code == 200 data = response.json() assert "errors" in data # The error should mention validation error_message = str(data["errors"]) assert "Invalid email format" in error_message or "email" in error_message.lower() async def test_introspect_member_type_enum(self, graphql_client): """Test GraphQL introspection returns MemberType enum.""" query = """ query { __type(name: "MemberType") { name kind enumValues { name } } } """ response = await graphql_client.post("/graphql", json={"query": query}) assert response.status_code == 200 data = response.json() assert "data" in data member_type = data["data"]["__type"] assert member_type["name"] == "MemberType" assert member_type["kind"] == "ENUM" enum_values = {ev["name"] for ev in member_type["enumValues"]} assert "INDIVIDUAL" in enum_values assert "ORGANIZATION" in enum_values