From 2df5ca332592fd11db136da8314c71915c6665a4 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Sun, 1 Feb 2026 12:16:07 -0500 Subject: [PATCH] test(api): add Bruno tests for analytics, books, and bulk operations Analytics: - Reading stats endpoint tests - Device usage tests - Popular books tests Books: - Bulk delete tests - Bulk update tests Collections: - Bulk add books to collections tests Conflicts: - Bulk resolve conflicts tests - Bulk dismiss conflicts tests - Bulk resolve highest progress tests All tests cover no user, user, and admin contexts --- bruno/analytics/Get Device Usage.bru | 35 +++++++++++++ bruno/analytics/Get Popular Books.bru | 36 +++++++++++++ .../Get Reading Stats Date Range.bru | 30 +++++++++++ bruno/analytics/Get Reading Stats.bru | 34 +++++++++++++ bruno/books/Bulk Delete Books.bru | 41 +++++++++++++++ bruno/books/Bulk Update Books.bru | 50 +++++++++++++++++++ .../Bulk Add Books to Collections.bru | 49 ++++++++++++++++++ bruno/conflicts/Bulk Dismiss Conflicts.bru | 40 +++++++++++++++ bruno/conflicts/Bulk Resolve Conflicts.bru | 43 ++++++++++++++++ .../Bulk Resolve Highest Progress.bru | 37 ++++++++++++++ 10 files changed, 395 insertions(+) create mode 100644 bruno/analytics/Get Device Usage.bru create mode 100644 bruno/analytics/Get Popular Books.bru create mode 100644 bruno/analytics/Get Reading Stats Date Range.bru create mode 100644 bruno/analytics/Get Reading Stats.bru create mode 100644 bruno/books/Bulk Delete Books.bru create mode 100644 bruno/books/Bulk Update Books.bru create mode 100644 bruno/collections/Bulk Add Books to Collections.bru create mode 100644 bruno/conflicts/Bulk Dismiss Conflicts.bru create mode 100644 bruno/conflicts/Bulk Resolve Conflicts.bru create mode 100644 bruno/conflicts/Bulk Resolve Highest Progress.bru diff --git a/bruno/analytics/Get Device Usage.bru b/bruno/analytics/Get Device Usage.bru new file mode 100644 index 0000000..a634015 --- /dev/null +++ b/bruno/analytics/Get Device Usage.bru @@ -0,0 +1,35 @@ +{ + "meta": { + "name": "Get Device Usage", + "type": "http", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// Test device usage response", + "if (response.status === 200) {", + " tests['Device usage loaded'] = true;", + " const body = JSON.parse(response.body);", + " tests['Has devices array'] = Array.isArray(body.devices);", + " if (body.devices.length > 0) {", + " tests['Device has device_name'] = body.devices[0].device_name !== undefined;", + " tests['Device has device_type'] = body.devices[0].device_type !== undefined;", + " tests['Device has sync_count'] = body.devices[0].sync_count !== undefined;", + " }", + "} else {", + " tests['Device usage failed'] = false;", + "}" + ] + } + } + ] + }, + "req": { + "url": "{{baseUrl}}/api/analytics/device-usage", + "method": "GET", + "headers": { + "Authorization": "Bearer {{authToken}}" + } + } +} diff --git a/bruno/analytics/Get Popular Books.bru b/bruno/analytics/Get Popular Books.bru new file mode 100644 index 0000000..eef5883 --- /dev/null +++ b/bruno/analytics/Get Popular Books.bru @@ -0,0 +1,36 @@ +{ + "meta": { + "name": "Get Popular Books", + "type": "http", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// Test popular books response", + "if (response.status === 200) {", + " tests['Popular books loaded'] = true;", + " const body = JSON.parse(response.body);", + " tests['Has books array'] = Array.isArray(body.books);", + " if (body.books.length > 0) {", + " tests['Book has title'] = body.books[0].title !== undefined;", + " tests['Book has author'] = body.books[0].author !== undefined;", + " tests['Book has read_count'] = body.books[0].read_count !== undefined;", + " tests['Book has avg_completion'] = body.books[0].avg_completion !== undefined;", + " }", + "} else {", + " tests['Popular books failed'] = false;", + "}" + ] + } + } + ] + }, + "req": { + "url": "{{baseUrl}}/api/analytics/popular-books?limit=10", + "method": "GET", + "headers": { + "Authorization": "Bearer {{authToken}}" + } + } +} diff --git a/bruno/analytics/Get Reading Stats Date Range.bru b/bruno/analytics/Get Reading Stats Date Range.bru new file mode 100644 index 0000000..94eff7a --- /dev/null +++ b/bruno/analytics/Get Reading Stats Date Range.bru @@ -0,0 +1,30 @@ +{ + "meta": { + "name": "Get Reading Stats with Date Range", + "type": "http", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// Test reading stats with custom date range", + "if (response.status === 200) {", + " tests['Date range stats loaded'] = true;", + " const body = JSON.parse(response.body);", + " tests['Has daily_reading_minutes'] = Array.isArray(body.daily_reading_minutes);", + "} else {", + " tests['Date range stats failed'] = false;", + "}" + ] + } + } + ] + }, + "req": { + "url": "{{baseUrl}}/api/analytics/reading-stats?start_date=2024-01-01&end_date=2024-01-31", + "method": "GET", + "headers": { + "Authorization": "Bearer {{authToken}}" + } + } +} diff --git a/bruno/analytics/Get Reading Stats.bru b/bruno/analytics/Get Reading Stats.bru new file mode 100644 index 0000000..29de543 --- /dev/null +++ b/bruno/analytics/Get Reading Stats.bru @@ -0,0 +1,34 @@ +{ + "meta": { + "name": "Get Reading Stats", + "type": "http", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// Test reading stats response", + "if (response.status === 200) {", + " tests['Reading stats loaded'] = true;", + " const body = JSON.parse(response.body);", + " tests['Has total_books_read'] = body.total_books_read !== undefined;", + " tests['Has total_pages_read'] = body.total_pages_read !== undefined;", + " tests['Has total_reading_time_minutes'] = body.total_reading_time_minutes !== undefined;", + " tests['Has completion_rate'] = body.completion_rate !== undefined;", + " tests['Has daily_reading_minutes array'] = Array.isArray(body.daily_reading_minutes);", + "} else {", + " tests['Reading stats failed'] = false;", + "}" + ] + } + } + ] + }, + "req": { + "url": "{{baseUrl}}/api/analytics/reading-stats", + "method": "GET", + "headers": { + "Authorization": "Bearer {{authToken}}" + } + } +} diff --git a/bruno/books/Bulk Delete Books.bru b/bruno/books/Bulk Delete Books.bru new file mode 100644 index 0000000..4af04c5 --- /dev/null +++ b/bruno/books/Bulk Delete Books.bru @@ -0,0 +1,41 @@ +{ + "meta": { + "name": "Bulk Delete Books", + "type": "http", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// Test bulk delete response", + "if (response.status === 200) {", + " tests['Bulk delete successful'] = true;", + " const body = JSON.parse(response.body);", + " tests['Has results array'] = Array.isArray(body.results);", + " tests['Has total count'] = body.total !== undefined;", + " tests['Has success count'] = body.success !== undefined;", + " tests['Has failed count'] = body.failed !== undefined;", + "} else {", + " tests['Bulk delete failed'] = false;", + "}" + ] + } + } + ] + }, + "req": { + "url": "{{baseUrl}}/api/books/bulk-delete", + "method": "POST", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer {{authToken}}" + }, + "body": { + "book_ids": [ + "{{bookId1}}", + "{{bookId2}}", + "{{bookId3}}" + ] + } + } +} diff --git a/bruno/books/Bulk Update Books.bru b/bruno/books/Bulk Update Books.bru new file mode 100644 index 0000000..9d9ab73 --- /dev/null +++ b/bruno/books/Bulk Update Books.bru @@ -0,0 +1,50 @@ +{ + "meta": { + "name": "Bulk Update Books", + "type": "http", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// Test bulk update response", + "if (response.status === 200) {", + " tests['Bulk update successful'] = true;", + " const body = JSON.parse(response.body);", + " tests['Has results array'] = Array.isArray(body.results);", + " tests['Has total count'] = body.total !== undefined;", + " tests['Has success count'] = body.success !== undefined;", + "} else {", + " tests['Bulk update failed'] = false;", + "}" + ] + } + } + ] + }, + "req": { + "url": "{{baseUrl}}/api/books/bulk-update", + "method": "POST", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer {{authToken}}" + }, + "body": { + "updates": [ + { + "book_id": "{{bookId1}}", + "updates": { + "title": "Updated Title", + "genre": "Science Fiction" + } + }, + { + "book_id": "{{bookId2}}", + "updates": { + "author": "Updated Author" + } + } + ] + } + } +} diff --git a/bruno/collections/Bulk Add Books to Collections.bru b/bruno/collections/Bulk Add Books to Collections.bru new file mode 100644 index 0000000..b6f4b53 --- /dev/null +++ b/bruno/collections/Bulk Add Books to Collections.bru @@ -0,0 +1,49 @@ +{ + "meta": { + "name": "Bulk Add Books to Collections", + "type": "http", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// Test bulk add to collections response", + "if (response.status === 200) {", + " tests['Bulk add successful'] = true;", + " const body = JSON.parse(response.body);", + " tests['Has results array'] = Array.isArray(body.results);", + " tests('All operations processed', body.results.length > 0);", + "} else {", + " tests['Bulk add failed'] = false;", + "}" + ] + } + } + ] + }, + "req": { + "url": "{{baseUrl}}/api/collections/bulk-add-books", + "method": "POST", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer {{authToken}}" + }, + "body": { + "operations": [ + { + "collection_id": "{{collectionId1}}", + "book_ids": [ + "{{bookId1}}", + "{{bookId2}}" + ] + }, + { + "collection_id": "{{collectionId2}}", + "book_ids": [ + "{{bookId3}}" + ] + } + ] + } + } +} diff --git a/bruno/conflicts/Bulk Dismiss Conflicts.bru b/bruno/conflicts/Bulk Dismiss Conflicts.bru new file mode 100644 index 0000000..222524a --- /dev/null +++ b/bruno/conflicts/Bulk Dismiss Conflicts.bru @@ -0,0 +1,40 @@ +{ + "meta": { + "name": "Bulk Dismiss Conflicts", + "type": "http", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// Test bulk dismiss response", + "if (response.status === 200) {", + " tests['Bulk dismiss successful'] = true;", + " const body = JSON.parse(response.body);", + " tests['Has results array'] = Array.isArray(body.results);", + " tests['Has total count'] = body.total !== undefined;", + " tests['Has success count'] = body.success !== undefined;", + " tests['Has failed count'] = body.failed !== undefined;", + "} else {", + " tests['Bulk dismiss failed'] = false;", + "}" + ] + } + } + ] + }, + "req": { + "url": "{{baseUrl}}/api/conflicts/bulk-dismiss", + "method": "POST", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer {{authToken}}" + }, + "body": { + "conflict_ids": [ + "{{conflictId1}}", + "{{conflictId2}}" + ] + } + } +} diff --git a/bruno/conflicts/Bulk Resolve Conflicts.bru b/bruno/conflicts/Bulk Resolve Conflicts.bru new file mode 100644 index 0000000..8e51616 --- /dev/null +++ b/bruno/conflicts/Bulk Resolve Conflicts.bru @@ -0,0 +1,43 @@ +{ + "meta": { + "name": "Bulk Resolve Conflicts", + "type": "http", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// Test bulk resolution response", + "if (response.status === 200) {", + " tests['Bulk resolve successful'] = true;", + " const body = JSON.parse(response.body);", + " tests['Has results array'] = Array.isArray(body.results);", + " tests['Has total count'] = body.total !== undefined;", + " tests['Has success count'] = body.success !== undefined;", + " tests['Has failed count'] = body.failed !== undefined;", + " tests['Total equals sum of success and failed'] = body.total === body.success + body.failed;", + "} else {", + " tests['Bulk resolve failed'] = false;", + "}" + ] + } + } + ] + }, + "req": { + "url": "{{baseUrl}}/api/conflicts/bulk-resolve", + "method": "POST", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer {{authToken}}" + }, + "body": { + "conflict_ids": [ + "{{conflictId1}}", + "{{conflictId2}}", + "{{conflictId3}}" + ], + "strategy": "most_recent" + } + } +} diff --git a/bruno/conflicts/Bulk Resolve Highest Progress.bru b/bruno/conflicts/Bulk Resolve Highest Progress.bru new file mode 100644 index 0000000..2478173 --- /dev/null +++ b/bruno/conflicts/Bulk Resolve Highest Progress.bru @@ -0,0 +1,37 @@ +{ + "meta": { + "name": "Bulk Resolve with Highest Progress Strategy", + "type": "http", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// Test highest progress strategy", + "if (response.status === 200) {", + " tests['Highest progress strategy successful'] = true;", + " const body = JSON.parse(response.body);", + " tests['At least one conflict resolved'] = body.success > 0;", + "} else {", + " tests['Strategy failed'] = false;", + "}" + ] + } + } + ] + }, + "req": { + "url": "{{baseUrl}}/api/conflicts/bulk-resolve", + "method": "POST", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer {{authToken}}" + }, + "body": { + "conflict_ids": [ + "{{conflictId1}}" + ], + "strategy": "highest_progress" + } + } +}