apollo-errors 0.7.0

Structured error handling with automatic format conversion
Documentation
//! Tests for automatic Option field handling
//!
//! Option<T> fields are automatically detected and:
//! - Omitted from output when None
//! - Serialized as the inner value when Some
use apollo_errors::FormatConfig;

mod common;

use apollo_errors::Error as ErrorTrait;
use common::{ErrorWithOptionalFields, ValidationError};
use insta::assert_json_snapshot;

// ============================================================================
// Enum tests - JSON format
// ============================================================================

#[test]
fn test_all_none_fields_omitted_json() {
    let error = ErrorWithOptionalFields::RequestFailed {
        request_id: None,
        retry_after: None,
    };
    let json = error.to_json(FormatConfig::default()).unwrap();
    assert_json_snapshot!(json, @r#"
    {
      "error": "request::failed",
      "message": "Request failed"
    }
    "#);
}

#[test]
fn test_all_some_fields_included_json() {
    let error = ErrorWithOptionalFields::RequestFailed {
        request_id: Some("req-123".to_string()),
        retry_after: Some(30),
    };
    let json = error.to_json(FormatConfig::default()).unwrap();
    assert_json_snapshot!(json, @r#"
    {
      "error": "request::failed",
      "message": "Request failed",
      "request_id": "req-123",
      "retry_after": 30
    }
    "#);
}

#[test]
fn test_mixed_optional_fields_json() {
    let error = ErrorWithOptionalFields::RequestFailed {
        request_id: Some("req-456".to_string()),
        retry_after: None,
    };
    let json = error.to_json(FormatConfig::default()).unwrap();
    assert_json_snapshot!(json, @r#"
    {
      "error": "request::failed",
      "message": "Request failed",
      "request_id": "req-456"
    }
    "#);
}

#[test]
fn test_mixed_required_and_optional_fields_json() {
    let error = ErrorWithOptionalFields::PartialFailure {
        succeeded: 5,
        failed: None,
    };
    let json = error.to_json(FormatConfig::default()).unwrap();
    assert_json_snapshot!(json, @r#"
    {
      "error": "request::partial",
      "message": "Partial failure",
      "succeeded": 5
    }
    "#);
}

#[test]
fn test_mixed_required_and_optional_fields_with_value_json() {
    let error = ErrorWithOptionalFields::PartialFailure {
        succeeded: 5,
        failed: Some(2),
    };
    let json = error.to_json(FormatConfig::default()).unwrap();
    assert_json_snapshot!(json, @r#"
    {
      "error": "request::partial",
      "failed": 2,
      "message": "Partial failure",
      "succeeded": 5
    }
    "#);
}

// ============================================================================
// Enum tests - GraphQL format
// ============================================================================

#[test]
fn test_all_none_fields_omitted_graphql() {
    let error = ErrorWithOptionalFields::RequestFailed {
        request_id: None,
        retry_after: None,
    };
    let graphql = error.to_graphql(FormatConfig::default()).unwrap();
    assert_json_snapshot!(graphql, @r#"
    {
      "extensions": {
        "code": "request::failed"
      },
      "message": "Request failed"
    }
    "#);
}

#[test]
fn test_all_some_fields_included_graphql() {
    let error = ErrorWithOptionalFields::RequestFailed {
        request_id: Some("req-123".to_string()),
        retry_after: Some(30),
    };
    let graphql = error.to_graphql(FormatConfig::default()).unwrap();
    assert_json_snapshot!(graphql, @r#"
    {
      "extensions": {
        "code": "request::failed",
        "request_id": "req-123",
        "retry_after": 30
      },
      "message": "Request failed"
    }
    "#);
}

// ============================================================================
// Enum tests - JSON-RPC format
// ============================================================================

#[test]
fn test_all_none_fields_omitted_jsonrpc() {
    let error = ErrorWithOptionalFields::RequestFailed {
        request_id: None,
        retry_after: None,
    };
    let jsonrpc = error.to_jsonrpc(FormatConfig::default()).unwrap();
    assert_json_snapshot!(jsonrpc, @r#"
    {
      "code": -32000,
      "data": {
        "diagnostic_code": "request::failed"
      },
      "message": "Request failed"
    }
    "#);
}

#[test]
fn test_all_some_fields_included_jsonrpc() {
    let error = ErrorWithOptionalFields::RequestFailed {
        request_id: Some("req-123".to_string()),
        retry_after: Some(30),
    };
    let jsonrpc = error.to_jsonrpc(FormatConfig::default()).unwrap();
    assert_json_snapshot!(jsonrpc, @r#"
    {
      "code": -32000,
      "data": {
        "diagnostic_code": "request::failed",
        "request_id": "req-123",
        "retry_after": 30
      },
      "message": "Request failed"
    }
    "#);
}

// ============================================================================
// Enum tests - HTML format
// ============================================================================

#[test]
fn test_all_none_fields_omitted_html() {
    let error = ErrorWithOptionalFields::RequestFailed {
        request_id: None,
        retry_after: None,
    };
    let html = error.to_html(FormatConfig::default());
    assert!(!html.contains("error-extensions"));
    assert!(!html.contains("request_id"));
    assert!(!html.contains("retry_after"));
}

#[test]
fn test_some_fields_included_html() {
    let error = ErrorWithOptionalFields::RequestFailed {
        request_id: Some("req-123".to_string()),
        retry_after: None,
    };
    let html = error.to_html(FormatConfig::default());
    assert!(html.contains("request_id"));
    assert!(html.contains("req-123"));
    assert!(!html.contains("retry_after"));
}

// ============================================================================
// Struct tests - JSON format
// ============================================================================

#[test]
fn test_struct_optional_field_none() {
    let error = ValidationError {
        field: "email".to_string(),
        suggestion: None,
    };
    let json = error.to_json(FormatConfig::default()).unwrap();
    assert_json_snapshot!(json, @r#"
    {
      "error": "validation::failed",
      "field": "email",
      "message": "Validation failed for email"
    }
    "#);
}

#[test]
fn test_struct_optional_field_some() {
    let error = ValidationError {
        field: "email".to_string(),
        suggestion: Some("Did you mean user@example.com?".to_string()),
    };
    let json = error.to_json(FormatConfig::default()).unwrap();
    assert_json_snapshot!(json, @r#"
    {
      "error": "validation::failed",
      "field": "email",
      "message": "Validation failed for email",
      "suggestion": "Did you mean user@example.com?"
    }
    "#);
}

// ============================================================================
// Struct tests - GraphQL format
// ============================================================================

#[test]
fn test_struct_optional_field_none_graphql() {
    let error = ValidationError {
        field: "email".to_string(),
        suggestion: None,
    };
    let graphql = error.to_graphql(FormatConfig::default()).unwrap();
    assert_json_snapshot!(graphql, @r#"
    {
      "extensions": {
        "code": "validation::failed",
        "field": "email"
      },
      "message": "Validation failed for email"
    }
    "#);
}

#[test]
fn test_struct_optional_field_some_graphql() {
    let error = ValidationError {
        field: "email".to_string(),
        suggestion: Some("Check the format".to_string()),
    };
    let graphql = error.to_graphql(FormatConfig::default()).unwrap();
    assert_json_snapshot!(graphql, @r#"
    {
      "extensions": {
        "code": "validation::failed",
        "field": "email",
        "suggestion": "Check the format"
      },
      "message": "Validation failed for email"
    }
    "#);
}

// ============================================================================
// Struct tests - HTML format
// ============================================================================

#[test]
fn test_struct_optional_field_none_html() {
    let error = ValidationError {
        field: "email".to_string(),
        suggestion: None,
    };
    let html = error.to_html(FormatConfig::default());
    assert!(html.contains("field"));
    assert!(html.contains("email"));
    assert!(!html.contains("suggestion"));
}

#[test]
fn test_struct_optional_field_some_html() {
    let error = ValidationError {
        field: "email".to_string(),
        suggestion: Some("Try again".to_string()),
    };
    let html = error.to_html(FormatConfig::default());
    assert!(html.contains("field"));
    assert!(html.contains("email"));
    assert!(html.contains("suggestion"));
    assert!(html.contains("Try again"));
}