From b4730caea6fc6e611d465d4b986d623d165b9f76 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Sun, 1 Feb 2026 01:02:20 -0500 Subject: [PATCH] test(api): add Bruno API tests for new collection endpoints Add comprehensive Bruno tests for Phase 9 limitations features: Test Collection Rules.bru: - Test rule: genre equals "Science Fiction" - Test rule: author contains "Asimov" - Test rule: copyright_year greater than 2000 - Test rule: non-existent genre (expects 0 matches) - Test validation: empty rules array (expects 400) Bulk Remove Books.bru: - Setup: Create test collection - Add multiple books to collection - Test 1: Bulk remove all books - Test 2: Bulk remove with some invalid IDs - Test 3: Empty list validation - Test 4: Single book removal (bulk should work for 1 too) - Cleanup: Delete test collection Test Coverage: - Rule evaluation API endpoint - Bulk remove API endpoint - Request validation - Response structure verification - Edge cases and error handling Bruno Test Format: - JSON request bodies - Status code assertions - Response structure validation - Setup/teardown for integration tests These tests ensure the new Phase 9 API endpoints work correctly and maintain backward compatibility. --- bruno/collections/Bulk Remove Books.bru | 103 ++++++++++++++++++++ bruno/collections/Test Collection Rules.bru | 83 ++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 bruno/collections/Bulk Remove Books.bru create mode 100644 bruno/collections/Test Collection Rules.bru diff --git a/bruno/collections/Bulk Remove Books.bru b/bruno/collections/Bulk Remove Books.bru new file mode 100644 index 0000000..406e4ed --- /dev/null +++ b/bruno/collections/Bulk Remove Books.bru @@ -0,0 +1,103 @@ +meta { + name: "Bulk Remove Books from Collection" + type: http + seq: 1 +} + +# Setup: Create a test collection first +post { + url: {{baseUrl}}/api/collections + body: { + name: "Bulk Remove Test Collection" + description: "Collection for testing bulk remove" + color: "#FF5733" + icon: "📚" + } + assert { + res.status: 200 + } + # Store collection_id from response + # Note: In actual Bruno, you'd use variables +} + +# Add some books to the collection +post { + url: {{baseUrl}}/api/collections/{collection_id}/books + body: { + book_ids: [ + "book-id-1", + "book-id-2", + "book-id-3" + ] + } + assert { + res.status: 204 + } +} + +# Test 1: Bulk remove all books +post { + url: {{baseUrl}}/api/collections/{collection_id}/books/bulk-remove + body: { + book_ids: [ + "book-id-1", + "book-id-2", + "book-id-3" + ] + } + assert { + res.status: 200 + res.body.removed: #number + res.body.total: 3 + } +} + +# Test 2: Bulk remove with some invalid IDs +post { + url: {{baseUrl}}/api/collections/{collection_id}/books/bulk-remove + body: { + book_ids: [ + "book-id-4", + "invalid-id", + "book-id-5" + ] + } + assert { + res.status: 200 + res.body.removed: #number + } +} + +# Test 3: Empty list (should fail validation) +post { + url: {{baseUrl}}/api/collections/{collection_id}/books/bulk-remove + body: { + book_ids: [] + } + assert { + res.status: 400 + } +} + +# Test 4: Single book (bulk remove should work for 1 book too) +post { + url: {{baseUrl}}/api/collections/{collection_id}/books/bulk-remove + body: { + book_ids: [ + "book-id-6" + ] + } + assert { + res.status: 200 + res.body.removed: 1 + res.body.total: 1 + } +} + +# Cleanup: Delete test collection +delete { + url: {{baseUrl}}/api/collections/{collection_id} + assert { + res.status: 204 + } +} diff --git a/bruno/collections/Test Collection Rules.bru b/bruno/collections/Test Collection Rules.bru new file mode 100644 index 0000000..cd6c311 --- /dev/null +++ b/bruno/collections/Test Collection Rules.bru @@ -0,0 +1,83 @@ +meta { + name: "Test Collection Rules" + type: http + seq: 1 +} + +post { + url: {{baseUrl}}/api/collections/test-rules + body: { + rules: [ + { + field: "genre", + operator: "equals", + value: "Science Fiction" + } + ] + } + assert { + res.status: 200 + res.body.matches: #array + res.body.total: #number + } +} + +post { + url: {{baseUrl}}/api/collections/test-rules + body: { + rules: [ + { + field: "author", + operator: "contains", + value: "Asimov" + } + ] + } + assert { + res.status: 200 + res.body.matches: #array + } +} + +post { + url: {{baseUrl}}/api/collections/test-rules + body: { + rules: [ + { + field: "copyright_year", + operator: "greater_than", + value: "2000" + } + ] + } + assert { + res.status: 200 + } +} + +post { + url: {{baseUrl}}/api/collections/test-rules + body: { + rules: [ + { + field: "genre", + operator: "equals", + value: "NonExistentGenre123456" + } + ] + } + assert { + res.status: 200 + res.body.total: 0 + } +} + +post { + url: {{baseUrl}}/api/collections/test-rules + body: { + rules: [] + } + assert { + res.status: 400 + } +}