Some checks failed
Test Suite / performance-tests (push) Has been cancelled
Test Suite / unit-tests (3.11) (push) Has been cancelled
Test Suite / unit-tests (3.12) (push) Has been cancelled
Test Suite / integration-tests (push) Has been cancelled
Test Suite / e2e-tests (push) Has been cancelled
Test Suite / code-quality (push) Has been cancelled
Test Suite / security-scan (push) Has been cancelled
Test Suite / test-summary (push) Has been cancelled
Added comprehensive GraphQL mutations for CRUD operations on markdown files and schemas. Key features: - Complete mutation schema with structured payload types - Markdown file mutations: add, update with front matter support - Schema mutations: add, update, delete with JSON validation - CLI integration with `graphql-mutate` command - Comprehensive error handling and validation - Full test coverage with 24 test cases - Updated documentation with mutation examples and API usage Resolves issue #10: Expose a GraphQL Write Interface 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
797 lines
25 KiB
Python
797 lines
25 KiB
Python
"""
|
|
Comprehensive tests for GraphQL mutations (Issue #10).
|
|
|
|
Tests all aspects of the GraphQL write interface including:
|
|
- Mutation schema validation
|
|
- Markdown file CRUD operations
|
|
- Schema CRUD operations
|
|
- Error handling
|
|
- CLI integration
|
|
"""
|
|
|
|
import pytest
|
|
import json
|
|
import sqlite3
|
|
import tempfile
|
|
import os
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from unittest.mock import Mock, patch
|
|
|
|
from markitect.graphql.schema import schema
|
|
from markitect.database import DatabaseManager
|
|
|
|
|
|
@pytest.fixture
|
|
def temp_db_path():
|
|
"""Create temporary database for testing."""
|
|
with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as f:
|
|
db_path = f.name
|
|
|
|
# Initialize database with test data
|
|
db_manager = DatabaseManager(db_path)
|
|
db_manager.initialize_database()
|
|
|
|
yield db_path
|
|
|
|
# Cleanup
|
|
os.unlink(db_path)
|
|
|
|
|
|
@pytest.fixture
|
|
def populated_db_path():
|
|
"""Create temporary database with some test data."""
|
|
with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as f:
|
|
db_path = f.name
|
|
|
|
# Initialize database with test data
|
|
db_manager = DatabaseManager(db_path)
|
|
db_manager.initialize_database()
|
|
|
|
# Add sample data
|
|
conn = sqlite3.connect(db_path)
|
|
cursor = conn.cursor()
|
|
|
|
# Sample markdown file
|
|
cursor.execute("""
|
|
INSERT INTO markdown_files (filename, content, front_matter, created_at)
|
|
VALUES (?, ?, ?, ?)
|
|
""", (
|
|
'existing.md',
|
|
'# Existing Document\n\nThis document already exists.',
|
|
'{"title": "Existing Document"}',
|
|
datetime.now().isoformat()
|
|
))
|
|
|
|
# Sample schema
|
|
cursor.execute("""
|
|
INSERT INTO schemas (filename, title, description, schema_content, created_at)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
""", (
|
|
'existing-schema.json',
|
|
'Existing Schema',
|
|
'A schema that already exists',
|
|
'{"type": "object", "properties": {"name": {"type": "string"}}}',
|
|
datetime.now().isoformat()
|
|
))
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
yield db_path
|
|
|
|
# Cleanup
|
|
os.unlink(db_path)
|
|
|
|
|
|
class TestGraphQLMutationSchema:
|
|
"""Test GraphQL mutation schema definition and validation."""
|
|
|
|
def test_schema_has_mutations(self):
|
|
"""Test that the GraphQL schema has mutations."""
|
|
result = schema.execute('''
|
|
{
|
|
__schema {
|
|
mutationType {
|
|
name
|
|
fields {
|
|
name
|
|
description
|
|
}
|
|
}
|
|
}
|
|
}
|
|
''')
|
|
|
|
assert result.errors is None
|
|
mutation_type = result.data['__schema']['mutationType']
|
|
assert mutation_type is not None
|
|
assert mutation_type['name'] == 'Mutation'
|
|
|
|
field_names = [field['name'] for field in mutation_type['fields']]
|
|
assert 'addMarkdownFile' in field_names
|
|
assert 'updateMarkdownFile' in field_names
|
|
assert 'addSchema' in field_names
|
|
assert 'updateSchema' in field_names
|
|
assert 'deleteSchema' in field_names
|
|
|
|
def test_add_markdown_file_mutation_signature(self):
|
|
"""Test addMarkdownFile mutation has correct signature."""
|
|
result = schema.execute('''
|
|
{
|
|
__schema {
|
|
mutationType {
|
|
fields {
|
|
name
|
|
args {
|
|
name
|
|
type {
|
|
name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
''')
|
|
|
|
mutation_fields = result.data['__schema']['mutationType']['fields']
|
|
add_file_field = next(f for f in mutation_fields if f['name'] == 'addMarkdownFile')
|
|
|
|
arg_names = [arg['name'] for arg in add_file_field['args']]
|
|
assert 'filename' in arg_names
|
|
assert 'content' in arg_names
|
|
|
|
def test_mutation_payload_types(self):
|
|
"""Test that mutation payload types have correct structure."""
|
|
result = schema.execute('''
|
|
{
|
|
__schema {
|
|
types {
|
|
name
|
|
fields {
|
|
name
|
|
type {
|
|
name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
''')
|
|
|
|
types = {t['name']: t for t in result.data['__schema']['types']}
|
|
|
|
# Check AddMarkdownFilePayload
|
|
payload = types.get('AddMarkdownFilePayload')
|
|
assert payload is not None
|
|
field_names = [f['name'] for f in payload['fields']]
|
|
assert 'markdownFile' in field_names
|
|
assert 'success' in field_names
|
|
assert 'errors' in field_names
|
|
|
|
|
|
class TestMarkdownFileMutations:
|
|
"""Test markdown file CRUD mutations."""
|
|
|
|
def test_add_markdown_file_success(self, temp_db_path):
|
|
"""Test successful markdown file creation."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=temp_db_path):
|
|
mutation = '''
|
|
mutation {
|
|
addMarkdownFile(
|
|
filename: "new-file.md"
|
|
content: "# New File\\n\\nThis is new content."
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
filename
|
|
content
|
|
wordCount
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
data = result.data['addMarkdownFile']
|
|
assert data['success'] is True
|
|
assert len(data['errors']) == 0
|
|
assert data['markdownFile'] is not None
|
|
assert data['markdownFile']['filename'] == 'new-file.md'
|
|
assert 'New File' in data['markdownFile']['content']
|
|
assert data['markdownFile']['wordCount'] > 0
|
|
|
|
def test_add_markdown_file_with_front_matter(self, temp_db_path):
|
|
"""Test markdown file creation with front matter."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=temp_db_path):
|
|
content_with_frontmatter = '''---
|
|
title: "Test Document"
|
|
author: "Test Author"
|
|
tags: ["test", "markdown"]
|
|
---
|
|
|
|
# Test Document
|
|
|
|
This is a test document with front matter.
|
|
'''
|
|
|
|
mutation = '''
|
|
mutation {
|
|
addMarkdownFile(
|
|
filename: "with-frontmatter.md"
|
|
content: "%s"
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
filename
|
|
hasFrontMatter
|
|
frontMatter {
|
|
key
|
|
value
|
|
}
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
''' % content_with_frontmatter.replace('\n', '\\n').replace('"', '\\"')
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
data = result.data['addMarkdownFile']
|
|
assert data['success'] is True
|
|
assert data['markdownFile']['hasFrontMatter'] is True
|
|
front_matter_keys = [fm['key'] for fm in data['markdownFile']['frontMatter']]
|
|
assert 'title' in front_matter_keys
|
|
assert 'author' in front_matter_keys
|
|
|
|
def test_add_markdown_file_duplicate_filename(self, populated_db_path):
|
|
"""Test adding a file with duplicate filename (should succeed as update)."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=populated_db_path):
|
|
mutation = '''
|
|
mutation {
|
|
addMarkdownFile(
|
|
filename: "existing.md"
|
|
content: "# Updated Content\\n\\nThis content replaces the existing."
|
|
) {
|
|
success
|
|
markdownFile {
|
|
filename
|
|
content
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
data = result.data['addMarkdownFile']
|
|
assert data['success'] is True
|
|
assert 'Updated Content' in data['markdownFile']['content']
|
|
|
|
def test_update_markdown_file_success(self, populated_db_path):
|
|
"""Test successful markdown file update."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=populated_db_path):
|
|
mutation = '''
|
|
mutation {
|
|
updateMarkdownFile(
|
|
id: 1
|
|
content: "# Updated Title\\n\\nThis content has been updated."
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
content
|
|
wordCount
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
data = result.data['updateMarkdownFile']
|
|
assert data['success'] is True
|
|
assert len(data['errors']) == 0
|
|
assert 'Updated Title' in data['markdownFile']['content']
|
|
|
|
def test_update_markdown_file_not_found(self, temp_db_path):
|
|
"""Test updating non-existent markdown file."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=temp_db_path):
|
|
mutation = '''
|
|
mutation {
|
|
updateMarkdownFile(
|
|
id: 999
|
|
content: "# This should fail"
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
data = result.data['updateMarkdownFile']
|
|
assert data['success'] is False
|
|
assert data['markdownFile'] is None
|
|
assert len(data['errors']) > 0
|
|
assert 'not found' in data['errors'][0].lower()
|
|
|
|
def test_update_markdown_file_no_content(self, populated_db_path):
|
|
"""Test updating markdown file without providing content."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=populated_db_path):
|
|
mutation = '''
|
|
mutation {
|
|
updateMarkdownFile(id: 1) {
|
|
success
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
data = result.data['updateMarkdownFile']
|
|
assert data['success'] is False
|
|
assert 'required' in data['errors'][0].lower()
|
|
|
|
|
|
class TestSchemaMutations:
|
|
"""Test JSON schema CRUD mutations."""
|
|
|
|
def test_add_schema_success(self, temp_db_path):
|
|
"""Test successful schema creation."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=temp_db_path):
|
|
schema_content = {
|
|
"type": "object",
|
|
"title": "User Schema",
|
|
"description": "Schema for user objects",
|
|
"properties": {
|
|
"name": {"type": "string"},
|
|
"age": {"type": "integer", "minimum": 0}
|
|
},
|
|
"required": ["name"]
|
|
}
|
|
|
|
mutation = '''
|
|
mutation {
|
|
addSchema(
|
|
filename: "user-schema.json"
|
|
schemaContent: "%s"
|
|
) {
|
|
success
|
|
schema {
|
|
id
|
|
filename
|
|
title
|
|
description
|
|
propertyCount
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
''' % json.dumps(schema_content).replace('"', '\\"')
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
data = result.data['addSchema']
|
|
assert data['success'] is True
|
|
assert len(data['errors']) == 0
|
|
assert data['schema']['filename'] == 'user-schema.json'
|
|
assert data['schema']['title'] == 'User Schema'
|
|
assert data['schema']['propertyCount'] == 2
|
|
|
|
def test_add_schema_invalid_json(self, temp_db_path):
|
|
"""Test adding schema with invalid JSON."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=temp_db_path):
|
|
mutation = '''
|
|
mutation {
|
|
addSchema(
|
|
filename: "invalid-schema.json"
|
|
schemaContent: "{ invalid json }"
|
|
) {
|
|
success
|
|
schema {
|
|
id
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
# GraphQL should reject invalid JSON at the schema validation level
|
|
assert result.errors is not None
|
|
assert len(result.errors) > 0
|
|
assert "Badly formed JSONString" in str(result.errors[0])
|
|
|
|
def test_update_schema_success(self, populated_db_path):
|
|
"""Test successful schema update."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=populated_db_path):
|
|
new_schema = {
|
|
"type": "object",
|
|
"title": "Updated Schema",
|
|
"properties": {
|
|
"name": {"type": "string"},
|
|
"email": {"type": "string", "format": "email"}
|
|
}
|
|
}
|
|
|
|
mutation = '''
|
|
mutation {
|
|
updateSchema(
|
|
id: 1
|
|
schemaContent: "%s"
|
|
) {
|
|
success
|
|
schema {
|
|
title
|
|
propertyCount
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
''' % json.dumps(new_schema).replace('"', '\\"')
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
data = result.data['updateSchema']
|
|
assert data['success'] is True
|
|
assert data['schema']['title'] == 'Updated Schema'
|
|
assert data['schema']['propertyCount'] == 2
|
|
|
|
def test_update_schema_not_found(self, temp_db_path):
|
|
"""Test updating non-existent schema."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=temp_db_path):
|
|
mutation = '''
|
|
mutation {
|
|
updateSchema(
|
|
id: 999
|
|
schemaContent: "{\\"type\\": \\"object\\"}"
|
|
) {
|
|
success
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
data = result.data['updateSchema']
|
|
assert data['success'] is False
|
|
assert 'not found' in data['errors'][0].lower()
|
|
|
|
def test_delete_schema_success(self, populated_db_path):
|
|
"""Test successful schema deletion."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=populated_db_path):
|
|
mutation = '''
|
|
mutation {
|
|
deleteSchema(filename: "existing-schema.json") {
|
|
success
|
|
deletedFilename
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
data = result.data['deleteSchema']
|
|
assert data['success'] is True
|
|
assert data['deletedFilename'] == 'existing-schema.json'
|
|
assert len(data['errors']) == 0
|
|
|
|
def test_delete_schema_not_found(self, temp_db_path):
|
|
"""Test deleting non-existent schema."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=temp_db_path):
|
|
mutation = '''
|
|
mutation {
|
|
deleteSchema(filename: "nonexistent.json") {
|
|
success
|
|
deletedFilename
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
data = result.data['deleteSchema']
|
|
assert data['success'] is False
|
|
assert data['deletedFilename'] is None
|
|
|
|
|
|
class TestMutationErrorHandling:
|
|
"""Test error handling in mutations."""
|
|
|
|
def test_database_error_handling(self, temp_db_path):
|
|
"""Test mutation behavior when database is unavailable."""
|
|
# Use a non-existent database path
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value='/nonexistent/path.db'):
|
|
mutation = '''
|
|
mutation {
|
|
addMarkdownFile(
|
|
filename: "test.md"
|
|
content: "# Test"
|
|
) {
|
|
success
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
data = result.data['addMarkdownFile']
|
|
assert data['success'] is False
|
|
assert len(data['errors']) > 0
|
|
|
|
def test_invalid_mutation_syntax(self):
|
|
"""Test handling of invalid mutation syntax."""
|
|
mutation = '''
|
|
mutation {
|
|
addMarkdownFile(filename: "test.md") {
|
|
success
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
# Should have errors due to missing required 'content' argument
|
|
assert result.errors is not None
|
|
|
|
def test_missing_required_arguments(self):
|
|
"""Test mutations with missing required arguments."""
|
|
mutation = '''
|
|
mutation {
|
|
addSchema(filename: "test.json") {
|
|
success
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
# Should have errors due to missing required 'schemaContent' argument
|
|
assert result.errors is not None
|
|
|
|
|
|
class TestMutationIntegration:
|
|
"""Test full integration of mutations with database."""
|
|
|
|
def test_crud_workflow(self, temp_db_path):
|
|
"""Test complete CRUD workflow for markdown files."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=temp_db_path):
|
|
# 1. Create a file
|
|
create_mutation = '''
|
|
mutation {
|
|
addMarkdownFile(
|
|
filename: "workflow-test.md"
|
|
content: "# Original Content\\n\\nOriginal text."
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
filename
|
|
content
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(create_mutation)
|
|
assert result.data['addMarkdownFile']['success'] is True
|
|
file_id = result.data['addMarkdownFile']['markdownFile']['id']
|
|
|
|
# 2. Update the file
|
|
update_mutation = '''
|
|
mutation {
|
|
updateMarkdownFile(
|
|
id: %d
|
|
content: "# Updated Content\\n\\nUpdated text."
|
|
) {
|
|
success
|
|
markdownFile {
|
|
content
|
|
}
|
|
}
|
|
}
|
|
''' % file_id
|
|
|
|
result = schema.execute(update_mutation)
|
|
assert result.data['updateMarkdownFile']['success'] is True
|
|
assert 'Updated Content' in result.data['updateMarkdownFile']['markdownFile']['content']
|
|
|
|
def test_schema_crud_workflow(self, temp_db_path):
|
|
"""Test complete CRUD workflow for schemas."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=temp_db_path):
|
|
# 1. Create a schema
|
|
create_mutation = '''
|
|
mutation {
|
|
addSchema(
|
|
filename: "workflow-schema.json"
|
|
schemaContent: "{\\"type\\": \\"object\\", \\"title\\": \\"Original\\"}"
|
|
) {
|
|
success
|
|
schema {
|
|
id
|
|
title
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(create_mutation)
|
|
assert result.data['addSchema']['success'] is True
|
|
schema_id = result.data['addSchema']['schema']['id']
|
|
|
|
# 2. Update the schema
|
|
update_mutation = '''
|
|
mutation {
|
|
updateSchema(
|
|
id: %d
|
|
schemaContent: "{\\"type\\": \\"object\\", \\"title\\": \\"Updated\\"}"
|
|
) {
|
|
success
|
|
schema {
|
|
title
|
|
}
|
|
}
|
|
}
|
|
''' % schema_id
|
|
|
|
result = schema.execute(update_mutation)
|
|
assert result.data['updateSchema']['success'] is True
|
|
assert result.data['updateSchema']['schema']['title'] == 'Updated'
|
|
|
|
# 3. Delete the schema
|
|
delete_mutation = '''
|
|
mutation {
|
|
deleteSchema(filename: "workflow-schema.json") {
|
|
success
|
|
deletedFilename
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(delete_mutation)
|
|
assert result.data['deleteSchema']['success'] is True
|
|
assert result.data['deleteSchema']['deletedFilename'] == 'workflow-schema.json'
|
|
|
|
|
|
class TestMutationCLI:
|
|
"""Test CLI integration for mutations."""
|
|
|
|
def test_graphql_mutate_command_available(self):
|
|
"""Test that graphql-mutate command is available."""
|
|
import subprocess
|
|
import sys
|
|
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "markitect.cli", "graphql-mutate", "--help"],
|
|
capture_output=True,
|
|
text=True
|
|
)
|
|
|
|
assert result.returncode == 0
|
|
assert "Execute GraphQL mutations" in result.stdout
|
|
assert "--local" in result.stdout
|
|
assert "--variables" in result.stdout
|
|
|
|
def test_mutation_examples_in_help(self):
|
|
"""Test that mutation examples are included in help."""
|
|
import subprocess
|
|
import sys
|
|
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "markitect.cli", "graphql-examples"],
|
|
capture_output=True,
|
|
text=True
|
|
)
|
|
|
|
assert result.returncode == 0
|
|
assert "Mutation Examples" in result.stdout
|
|
assert "addMarkdownFile" in result.stdout
|
|
assert "updateMarkdownFile" in result.stdout
|
|
assert "addSchema" in result.stdout
|
|
assert "deleteSchema" in result.stdout
|
|
|
|
|
|
class TestMutationPayloads:
|
|
"""Test mutation payload structures."""
|
|
|
|
def test_add_markdown_file_payload_structure(self, temp_db_path):
|
|
"""Test AddMarkdownFilePayload has correct structure."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value=temp_db_path):
|
|
mutation = '''
|
|
mutation {
|
|
addMarkdownFile(
|
|
filename: "payload-test.md"
|
|
content: "# Payload Test"
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
filename
|
|
content
|
|
wordCount
|
|
lineCount
|
|
hasFrontMatter
|
|
createdAt
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
payload = result.data['addMarkdownFile']
|
|
|
|
# Check payload structure
|
|
assert isinstance(payload['success'], bool)
|
|
assert isinstance(payload['errors'], list)
|
|
|
|
if payload['success']:
|
|
md_file = payload['markdownFile']
|
|
assert md_file is not None
|
|
assert isinstance(md_file['id'], int)
|
|
assert isinstance(md_file['filename'], str)
|
|
assert isinstance(md_file['wordCount'], int)
|
|
assert isinstance(md_file['lineCount'], int)
|
|
assert isinstance(md_file['hasFrontMatter'], bool)
|
|
|
|
def test_error_payload_structure(self, temp_db_path):
|
|
"""Test error payloads have correct structure."""
|
|
with patch('markitect.graphql.resolvers.get_default_database_path', return_value='/nonexistent/path.db'):
|
|
mutation = '''
|
|
mutation {
|
|
addMarkdownFile(
|
|
filename: "error-test.md"
|
|
content: "# Error Test"
|
|
) {
|
|
success
|
|
markdownFile {
|
|
id
|
|
}
|
|
errors
|
|
}
|
|
}
|
|
'''
|
|
|
|
result = schema.execute(mutation)
|
|
|
|
assert result.errors is None
|
|
payload = result.data['addMarkdownFile']
|
|
|
|
assert payload['success'] is False
|
|
assert payload['markdownFile'] is None
|
|
assert isinstance(payload['errors'], list)
|
|
assert len(payload['errors']) > 0
|
|
assert all(isinstance(error, str) for error in payload['errors']) |