@roomi-fields/notebooklm-mcp 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/LICENSE +22 -22
  2. package/README.md +2 -0
  3. package/deployment/INDEX.md +292 -0
  4. package/deployment/PACKAGE-FILES.txt +180 -0
  5. package/deployment/QUICK-START.md +100 -0
  6. package/deployment/docs/01-INSTALL.md +611 -0
  7. package/deployment/docs/02-CONFIGURATION.md +404 -0
  8. package/deployment/docs/03-API.md +1691 -0
  9. package/deployment/docs/04-N8N-INTEGRATION.md +373 -0
  10. package/deployment/docs/05-TROUBLESHOOTING.md +429 -0
  11. package/deployment/docs/06-NOTEBOOK-LIBRARY.md +692 -0
  12. package/deployment/docs/07-AUTO-DISCOVERY.md +236 -0
  13. package/deployment/docs/08-WSL-USAGE.md +363 -0
  14. package/deployment/docs/09-MULTI-INTERFACE.md +293 -0
  15. package/deployment/docs/10-CONTENT-MANAGEMENT.md +421 -0
  16. package/deployment/docs/11-MULTI-ACCOUNT.md +295 -0
  17. package/deployment/docs/README.md +207 -0
  18. package/deployment/scripts/README.md +564 -0
  19. package/deployment/scripts/install.ps1 +114 -0
  20. package/deployment/scripts/setup-auth.ps1 +217 -0
  21. package/deployment/scripts/start-server.ps1 +72 -0
  22. package/deployment/scripts/stop-server.ps1 +51 -0
  23. package/deployment/scripts/test-api.ps1 +651 -0
  24. package/deployment/scripts/test-auth.ps1 +323 -0
  25. package/deployment/scripts/test-auto-discovery.ps1 +295 -0
  26. package/deployment/scripts/test-cors.ps1 +398 -0
  27. package/deployment/scripts/test-errors.ps1 +581 -0
  28. package/deployment/scripts/test-server.ps1 +140 -0
  29. package/deployment/scripts/test-sessions.ps1 +426 -0
  30. package/deployment/scripts/test-validation.ps1 +299 -0
  31. package/dist/cli/accounts.js.map +1 -1
  32. package/dist/config.d.ts +1 -0
  33. package/dist/config.d.ts.map +1 -1
  34. package/dist/config.js +15 -0
  35. package/dist/config.js.map +1 -1
  36. package/dist/content/content-manager.d.ts.map +1 -1
  37. package/dist/content/content-manager.js +113 -118
  38. package/dist/content/content-manager.js.map +1 -1
  39. package/dist/i18n/en.json +120 -0
  40. package/dist/i18n/fr.json +120 -0
  41. package/dist/i18n/index.d.ts +168 -0
  42. package/dist/i18n/index.d.ts.map +1 -0
  43. package/dist/i18n/index.js +213 -0
  44. package/dist/i18n/index.js.map +1 -0
  45. package/dist/session/browser-session.d.ts.map +1 -1
  46. package/dist/session/browser-session.js +1 -0
  47. package/dist/session/browser-session.js.map +1 -1
  48. package/dist/session/shared-context-manager.d.ts.map +1 -1
  49. package/dist/session/shared-context-manager.js +2 -0
  50. package/dist/session/shared-context-manager.js.map +1 -1
  51. package/docs/ADDING_A_LANGUAGE.md +209 -0
  52. package/package.json +6 -3
  53. package/scripts/archive/add-and-activate-notebook.ps1 +31 -0
  54. package/scripts/archive/add-new-notebook.ps1 +25 -0
  55. package/scripts/archive/add-rom1pey.ps1 +2 -0
  56. package/scripts/archive/add-rpmonster.ps1 +2 -0
  57. package/scripts/archive/add-source-debug.ps1 +11 -0
  58. package/scripts/archive/add-source-e2e.ps1 +28 -0
  59. package/scripts/archive/add-source-visible.ps1 +11 -0
  60. package/scripts/archive/add-test-notebook.ps1 +13 -0
  61. package/scripts/archive/add-test-source.ps1 +50 -0
  62. package/scripts/archive/capture-screen.ps1 +11 -0
  63. package/scripts/archive/change-language.mjs +45 -0
  64. package/scripts/archive/change-language.ts +44 -0
  65. package/scripts/archive/check-account.ps1 +19 -0
  66. package/scripts/archive/check-notebook-2.ps1 +8 -0
  67. package/scripts/archive/check-test-notebook.ps1 +11 -0
  68. package/scripts/archive/create-notebook-auto.ps1 +31 -0
  69. package/scripts/archive/create-notebook.ps1 +8 -0
  70. package/scripts/archive/create-rom1pey-notebook.ps1 +19 -0
  71. package/scripts/archive/create-rom1pey.ps1 +8 -0
  72. package/scripts/archive/create-test-notebook-fresh.ps1 +21 -0
  73. package/scripts/archive/create-test-notebook.ps1 +16 -0
  74. package/scripts/archive/debug-add-source-auto.ps1 +29 -0
  75. package/scripts/archive/debug-add-source.ps1 +19 -0
  76. package/scripts/archive/debug-add-text-source.ps1 +47 -0
  77. package/scripts/archive/debug-home.ps1 +10 -0
  78. package/scripts/archive/debug-selectors.ps1 +55 -0
  79. package/scripts/archive/debug-sources-panel.ps1 +22 -0
  80. package/scripts/archive/debug-ui.ps1 +17 -0
  81. package/scripts/archive/discover-home.ps1 +26 -0
  82. package/scripts/archive/kill-automation-chrome.ps1 +37 -0
  83. package/scripts/archive/list-my-notebooks.ps1 +27 -0
  84. package/scripts/archive/navigate-home-visible.ps1 +23 -0
  85. package/scripts/archive/navigate-home.ps1 +15 -0
  86. package/scripts/archive/run-e2e-english.ps1 +111 -0
  87. package/scripts/archive/run-e2e-rom1pey-v2.ps1 +122 -0
  88. package/scripts/archive/run-e2e-rom1pey.ps1 +117 -0
  89. package/scripts/archive/setup-english-test.ps1 +36 -0
  90. package/scripts/archive/setup-test-notebook.ps1 +71 -0
  91. package/scripts/archive/simple-add-source.ps1 +14 -0
  92. package/scripts/archive/t10.ps1 +2 -0
  93. package/scripts/archive/t20.ps1 +4 -0
  94. package/scripts/archive/t30.ps1 +9 -0
  95. package/scripts/archive/t31.ps1 +11 -0
  96. package/scripts/archive/t32.ps1 +6 -0
  97. package/scripts/archive/t39.ps1 +5 -0
  98. package/scripts/archive/t40.ps1 +5 -0
  99. package/scripts/archive/t53.ps1 +12 -0
  100. package/scripts/archive/t54.ps1 +12 -0
  101. package/scripts/archive/t55.ps1 +11 -0
  102. package/scripts/archive/t9.ps1 +1 -0
  103. package/scripts/archive/test-access.ps1 +28 -0
  104. package/scripts/archive/test-add-delete-source.ps1 +64 -0
  105. package/scripts/archive/test-add-source-visible.ps1 +16 -0
  106. package/scripts/archive/test-add-source.ps1 +19 -0
  107. package/scripts/archive/test-add-text-debug.ps1 +28 -0
  108. package/scripts/archive/test-add-text-source.ps1 +8 -0
  109. package/scripts/archive/test-add-url-source.ps1 +7 -0
  110. package/scripts/archive/test-ask-ascii.ps1 +20 -0
  111. package/scripts/archive/test-ask-cnv.ps1 +20 -0
  112. package/scripts/archive/test-ask-headed.ps1 +51 -0
  113. package/scripts/archive/test-ask-ifs.ps1 +16 -0
  114. package/scripts/archive/test-ask-now.ps1 +24 -0
  115. package/scripts/archive/test-ask-real.ps1 +19 -0
  116. package/scripts/archive/test-ask-visible.ps1 +20 -0
  117. package/scripts/archive/test-create-notebook.ps1 +8 -0
  118. package/scripts/archive/test-create-then-add.ps1 +17 -0
  119. package/scripts/archive/test-delete-source.ps1 +41 -0
  120. package/scripts/archive/test-e2e-notebook.ps1 +21 -0
  121. package/scripts/archive/test-english-notebook.ps1 +20 -0
  122. package/scripts/archive/test-english.ps1 +7 -0
  123. package/scripts/archive/test-full-custom-instructions.ps1 +40 -0
  124. package/scripts/archive/test-full-infographic.ps1 +34 -0
  125. package/scripts/archive/test-full-language.ps1 +21 -0
  126. package/scripts/archive/test-full-presentation.ps1 +85 -0
  127. package/scripts/archive/test-full-report.ps1 +34 -0
  128. package/scripts/archive/test-full-source-selection.ps1 +35 -0
  129. package/scripts/archive/test-full-video-brief.ps1 +22 -0
  130. package/scripts/archive/test-full-video-explainer.ps1 +22 -0
  131. package/scripts/archive/test-full-video-styles.ps1 +37 -0
  132. package/scripts/archive/test-generate-report.ps1 +15 -0
  133. package/scripts/archive/test-generate-study-guide.ps1 +11 -0
  134. package/scripts/archive/test-headed-ask.ps1 +13 -0
  135. package/scripts/archive/test-headed-now.ps1 +9 -0
  136. package/scripts/archive/test-headed.ps1 +9 -0
  137. package/scripts/archive/test-hello.ps1 +7 -0
  138. package/scripts/archive/test-i18n-studio.ps1 +8 -0
  139. package/scripts/archive/test-i18n.ps1 +7 -0
  140. package/scripts/archive/test-manual-headed.ps1 +26 -0
  141. package/scripts/archive/test-mathieu-quota.ps1 +8 -0
  142. package/scripts/archive/test-notebook-1.ps1 +10 -0
  143. package/scripts/archive/test-notebook-2-sources.ps1 +12 -0
  144. package/scripts/archive/test-notebook1.ps1 +14 -0
  145. package/scripts/archive/test-personal-notebook.ps1 +14 -0
  146. package/scripts/archive/test-rate-limit.ps1 +19 -0
  147. package/scripts/archive/test-real-ask.ps1 +50 -0
  148. package/scripts/archive/test-real-ask2.ps1 +30 -0
  149. package/scripts/archive/test-rom1pey.ps1 +7 -0
  150. package/scripts/archive/test-rotation-complete.ps1 +14 -0
  151. package/scripts/archive/test-rotation.ps1 +8 -0
  152. package/scripts/archive/test-show-browser.ps1 +39 -0
  153. package/scripts/archive/test-update-notebook.ps1 +4 -0
  154. package/scripts/archive/verify-language-slow.ps1 +21 -0
  155. package/scripts/archive/verify-language.ps1 +15 -0
  156. package/scripts/check-server.ps1 +46 -0
  157. package/scripts/mcp-wsl-helper.sh +146 -0
  158. package/scripts/start-server.ps1 +94 -0
  159. package/scripts/stop-server.ps1 +30 -0
  160. package/scripts/switch-account-language.sh +191 -0
  161. package/scripts/test-account.ps1 +58 -0
@@ -0,0 +1,581 @@
1
+ #!/usr/bin/env pwsh
2
+ #Requires -Version 5.1
3
+
4
+ <#
5
+ .SYNOPSIS
6
+ Error case testing script for NotebookLM MCP HTTP Server API
7
+
8
+ .DESCRIPTION
9
+ Tests all error cases to verify that the API returns the correct errors
10
+
11
+ .PARAMETER BaseUrl
12
+ Base URL of the server (default: http://localhost:3000)
13
+
14
+ .EXAMPLE
15
+ .\test-errors.ps1
16
+ Runs all error tests
17
+
18
+ .EXAMPLE
19
+ .\test-errors.ps1 -BaseUrl "http://localhost:8080"
20
+ Runs tests on a server at a different port
21
+
22
+ .NOTES
23
+ Prerequisite: The server must be started
24
+ #>
25
+
26
+ param(
27
+ [string]$BaseUrl = "http://localhost:3000"
28
+ )
29
+
30
+ # Colors for logs
31
+ function Write-TestHeader {
32
+ param([string]$Message, [int]$Number, [int]$Total)
33
+ Write-Host "`n" -NoNewline
34
+ Write-Host "═══════════════════════════════════════════════════════" -ForegroundColor Magenta
35
+ Write-Host " [$Number/$Total] $Message" -ForegroundColor Cyan
36
+ Write-Host "═══════════════════════════════════════════════════════" -ForegroundColor Magenta
37
+ }
38
+
39
+ function Write-Success {
40
+ param([string]$Message)
41
+ Write-Host "✓ $Message" -ForegroundColor Green
42
+ }
43
+
44
+ function Write-Info {
45
+ param([string]$Message)
46
+ Write-Host "ℹ $Message" -ForegroundColor Yellow
47
+ }
48
+
49
+ function Write-ErrorExpected {
50
+ param([string]$Message)
51
+ Write-Host "✓ Expected error: $Message" -ForegroundColor Green
52
+ }
53
+
54
+ function Write-ErrorUnexpected {
55
+ param([string]$Message)
56
+ Write-Host "✗ Unexpected error: $Message" -ForegroundColor Red
57
+ }
58
+
59
+ # Banner
60
+ Clear-Host
61
+ Write-Host "`n" -NoNewline
62
+ Write-Host "╔════════════════════════════════════════════════════════╗" -ForegroundColor Magenta
63
+ Write-Host "║ ║" -ForegroundColor Magenta
64
+ Write-Host "║ ERROR CASE TESTS - HTTP API ║" -ForegroundColor Cyan
65
+ Write-Host "║ ║" -ForegroundColor Magenta
66
+ Write-Host "╚════════════════════════════════════════════════════════╝" -ForegroundColor Magenta
67
+ Write-Host ""
68
+
69
+ # Check that the server is accessible
70
+ Write-Host "Checking connection to server..." -ForegroundColor Yellow
71
+ try {
72
+ $null = Invoke-RestMethod -Uri "$BaseUrl/health" -TimeoutSec 5
73
+ Write-Success "Server accessible at $BaseUrl"
74
+ } catch {
75
+ Write-ErrorUnexpected "Unable to connect to server at $BaseUrl"
76
+ Write-Host "Make sure the server is started" -ForegroundColor Yellow
77
+ exit 1
78
+ }
79
+
80
+ # Get existing notebooks for tests
81
+ $notebooks = Invoke-RestMethod -Uri "$BaseUrl/notebooks"
82
+ $existingNotebook = if ($notebooks.data.notebooks.Count -gt 0) { $notebooks.data.notebooks[0] } else { $null }
83
+
84
+ $TotalTests = 12
85
+ $PassedTests = 0
86
+ $FailedTests = 0
87
+
88
+ # =============================================================================
89
+ # TEST 1: POST /ask - Missing question
90
+ # =============================================================================
91
+ Write-TestHeader "POST /ask - Error: missing question" 1 $TotalTests
92
+
93
+ try {
94
+ $body = @{} | ConvertTo-Json
95
+ $null = Invoke-RestMethod -Uri "$BaseUrl/ask" -Method Post -Body $body -ContentType "application/json"
96
+ Write-ErrorUnexpected "Should return a 400 error"
97
+ $FailedTests++
98
+ } catch {
99
+ if ($_.Exception.Response.StatusCode -eq 400 -or $_.Exception.Response.StatusCode -eq 'BadRequest') {
100
+ $errorResponse = $_.ErrorDetails.Message | ConvertFrom-Json
101
+ Write-ErrorExpected "$($errorResponse.error)"
102
+ if ($errorResponse.error -like "*question*") {
103
+ Write-Success "Correct error message (mentions 'question')"
104
+ $PassedTests++
105
+ } else {
106
+ Write-ErrorUnexpected "Error message doesn't mention the missing field"
107
+ $FailedTests++
108
+ }
109
+ } else {
110
+ Write-ErrorUnexpected "Incorrect HTTP code: $($_.Exception.Response.StatusCode)"
111
+ $FailedTests++
112
+ }
113
+ }
114
+
115
+ # =============================================================================
116
+ # TEST 2: POST /ask - Non-existent notebook (invalid notebook_id)
117
+ # =============================================================================
118
+ Write-TestHeader "POST /ask - Error: non-existent notebook_id" 2 $TotalTests
119
+
120
+ try {
121
+ $body = @{
122
+ question = "Test question"
123
+ notebook_id = "notebook-that-does-not-exist-xyz-123"
124
+ } | ConvertTo-Json
125
+
126
+ $result = Invoke-RestMethod -Uri "$BaseUrl/ask" -Method Post -Body $body -ContentType "application/json"
127
+
128
+ # If no HTTP exception, check success: false
129
+ if ($result.success -eq $false) {
130
+ Write-ErrorExpected "$($result.error.Substring(0, [Math]::Min(80, $result.error.Length)))..."
131
+
132
+ if ($result.error -like "*not found*" -or $result.error -like "*introuvable*") {
133
+ Write-Success "Correct error message (notebook not found)"
134
+ $PassedTests++
135
+ } else {
136
+ Write-ErrorUnexpected "Unexpected error message"
137
+ $FailedTests++
138
+ }
139
+ } else {
140
+ Write-ErrorUnexpected "Should return success: false"
141
+ $FailedTests++
142
+ }
143
+ } catch {
144
+ # HTTP exception (500, etc.)
145
+ $errorResponse = $_.ErrorDetails.Message | ConvertFrom-Json
146
+ Write-ErrorExpected "$($errorResponse.error.Substring(0, [Math]::Min(80, $errorResponse.error.Length)))..."
147
+
148
+ if ($errorResponse.error -like "*not found*" -or $errorResponse.error -like "*introuvable*") {
149
+ Write-Success "Correct error message (notebook not found)"
150
+ $PassedTests++
151
+ } else {
152
+ Write-ErrorUnexpected "Unexpected error message"
153
+ $FailedTests++
154
+ }
155
+ }
156
+
157
+ # =============================================================================
158
+ # TEST 3: POST /ask - No notebook configured and no notebook_url
159
+ # =============================================================================
160
+ Write-TestHeader "POST /ask - Error: no notebook (if library empty)" 3 $TotalTests
161
+
162
+ if ($notebooks.data.notebooks.Count -eq 0) {
163
+ try {
164
+ $body = @{
165
+ question = "Test question without notebook"
166
+ } | ConvertTo-Json
167
+
168
+ $null = Invoke-RestMethod -Uri "$BaseUrl/ask" -Method Post -Body $body -ContentType "application/json"
169
+ Write-ErrorUnexpected "Should return an error"
170
+ $FailedTests++
171
+ } catch {
172
+ $errorResponse = $_.ErrorDetails.Message | ConvertFrom-Json
173
+ Write-ErrorExpected "$($errorResponse.error.Substring(0, [Math]::Min(80, $errorResponse.error.Length)))..."
174
+
175
+ if ($errorResponse.error -like "*No notebooks*" -or $errorResponse.error -like "*Aucun notebook*") {
176
+ Write-Success "Correct error message (no notebooks)"
177
+ $PassedTests++
178
+ } else {
179
+ Write-ErrorUnexpected "Unexpected error message"
180
+ $FailedTests++
181
+ }
182
+ }
183
+ } else {
184
+ Write-Info "Test skipped: notebooks are configured (cannot test 'no notebook')"
185
+ Write-Info "To test this case: temporarily delete all your notebooks"
186
+ }
187
+
188
+ # =============================================================================
189
+ # TEST 4: POST /notebooks - Missing URL
190
+ # =============================================================================
191
+ Write-TestHeader "POST /notebooks - Error: missing URL" 4 $TotalTests
192
+
193
+ try {
194
+ $body = @{
195
+ name = "Test Notebook"
196
+ description = "Test"
197
+ topics = @("test")
198
+ } | ConvertTo-Json
199
+
200
+ $null = Invoke-RestMethod -Uri "$BaseUrl/notebooks" -Method Post -Body $body -ContentType "application/json"
201
+ Write-ErrorUnexpected "Should return a 400 error"
202
+ $FailedTests++
203
+ } catch {
204
+ if ($_.Exception.Response.StatusCode -eq 400 -or $_.Exception.Response.StatusCode -eq 'BadRequest') {
205
+ $errorResponse = $_.ErrorDetails.Message | ConvertFrom-Json
206
+ Write-ErrorExpected "$($errorResponse.error)"
207
+ if ($errorResponse.error -like "*url*") {
208
+ Write-Success "Correct error message (mentions 'url')"
209
+ $PassedTests++
210
+ } else {
211
+ Write-ErrorUnexpected "Error message doesn't mention the missing field"
212
+ $FailedTests++
213
+ }
214
+ } else {
215
+ Write-ErrorUnexpected "Incorrect HTTP code"
216
+ $FailedTests++
217
+ }
218
+ }
219
+
220
+ # =============================================================================
221
+ # TEST 5: POST /notebooks - Missing name
222
+ # =============================================================================
223
+ Write-TestHeader "POST /notebooks - Error: missing name" 5 $TotalTests
224
+
225
+ try {
226
+ $body = @{
227
+ url = "https://notebooklm.google.com/notebook/test-123"
228
+ description = "Test"
229
+ topics = @("test")
230
+ } | ConvertTo-Json
231
+
232
+ $null = Invoke-RestMethod -Uri "$BaseUrl/notebooks" -Method Post -Body $body -ContentType "application/json"
233
+ Write-ErrorUnexpected "Should return a 400 error"
234
+ $FailedTests++
235
+ } catch {
236
+ if ($_.Exception.Response.StatusCode -eq 400 -or $_.Exception.Response.StatusCode -eq 'BadRequest') {
237
+ $errorResponse = $_.ErrorDetails.Message | ConvertFrom-Json
238
+ Write-ErrorExpected "$($errorResponse.error)"
239
+ if ($errorResponse.error -like "*name*") {
240
+ Write-Success "Correct error message (mentions 'name')"
241
+ $PassedTests++
242
+ } else {
243
+ Write-ErrorUnexpected "Error message doesn't mention the missing field"
244
+ $FailedTests++
245
+ }
246
+ } else {
247
+ Write-ErrorUnexpected "Incorrect HTTP code"
248
+ $FailedTests++
249
+ }
250
+ }
251
+
252
+ # =============================================================================
253
+ # TEST 6: POST /notebooks - Invalid URL (incorrect format)
254
+ # =============================================================================
255
+ Write-TestHeader "POST /notebooks - Error: invalid URL format" 6 $TotalTests
256
+
257
+ try {
258
+ $body = @{
259
+ url = "https://example.com/not-a-notebook"
260
+ name = "Test Invalid URL"
261
+ description = "Test"
262
+ topics = @("test")
263
+ } | ConvertTo-Json
264
+
265
+ $result = Invoke-RestMethod -Uri "$BaseUrl/notebooks" -Method Post -Body $body -ContentType "application/json"
266
+
267
+ # If no HTTP exception, check success: false
268
+ if ($result.success -eq $false) {
269
+ Write-ErrorExpected "$($result.error.Substring(0, [Math]::Min(80, $result.error.Length)))..."
270
+
271
+ # Accept various error messages for invalid URL: "Invalid URL", "format", "NotebookLM URL", "notebooklm.google.com"
272
+ if ($result.error -like "*Invalid*URL*" -or $result.error -like "*format*" -or $result.error -like "*NotebookLM*URL*" -or $result.error -like "*notebooklm.google.com*") {
273
+ Write-Success "Correct error message (invalid URL)"
274
+ $PassedTests++
275
+ } else {
276
+ Write-ErrorUnexpected "Unexpected error message"
277
+ $FailedTests++
278
+ }
279
+ } else {
280
+ Write-ErrorUnexpected "Should return success: false"
281
+ $FailedTests++
282
+ }
283
+ } catch {
284
+ # HTTP exception (500, etc.)
285
+ $errorResponse = $_.ErrorDetails.Message | ConvertFrom-Json
286
+ Write-ErrorExpected "$($errorResponse.error.Substring(0, [Math]::Min(80, $errorResponse.error.Length)))..."
287
+
288
+ # Accept various error messages for invalid URL: "Invalid URL", "format", "NotebookLM URL", "notebooklm.google.com"
289
+ if ($errorResponse.error -like "*Invalid*URL*" -or $errorResponse.error -like "*format*" -or $errorResponse.error -like "*NotebookLM*URL*" -or $errorResponse.error -like "*notebooklm.google.com*") {
290
+ Write-Success "Correct error message (invalid URL)"
291
+ $PassedTests++
292
+ } else {
293
+ Write-ErrorUnexpected "Unexpected error message"
294
+ $FailedTests++
295
+ }
296
+ }
297
+
298
+ # =============================================================================
299
+ # TEST 7: POST /notebooks - Duplicate name
300
+ # =============================================================================
301
+ Write-TestHeader "POST /notebooks - Error: name already in use" 7 $TotalTests
302
+
303
+ if ($existingNotebook) {
304
+ Write-Info "Testing with existing notebook: $($existingNotebook.name)"
305
+
306
+ try {
307
+ $body = @{
308
+ url = "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000000"
309
+ name = $existingNotebook.name # Use the same name
310
+ description = "Test duplicate"
311
+ topics = @("test")
312
+ } | ConvertTo-Json
313
+
314
+ $result = Invoke-RestMethod -Uri "$BaseUrl/notebooks" -Method Post -Body $body -ContentType "application/json"
315
+
316
+ # If no HTTP exception, check success: false
317
+ if ($result.success -eq $false) {
318
+ Write-ErrorExpected "$($result.error.Substring(0, [Math]::Min(80, $result.error.Length)))..."
319
+
320
+ if ($result.error -like "*already exists*" -or $result.error -like "*déjà*") {
321
+ Write-Success "Correct error message (name already in use)"
322
+ $PassedTests++
323
+ } else {
324
+ Write-ErrorUnexpected "Unexpected error message"
325
+ $FailedTests++
326
+ }
327
+ } else {
328
+ Write-ErrorUnexpected "Should return success: false"
329
+ $FailedTests++
330
+ }
331
+ } catch {
332
+ # HTTP exception (500, etc.)
333
+ $errorResponse = $_.ErrorDetails.Message | ConvertFrom-Json
334
+ Write-ErrorExpected "$($errorResponse.error.Substring(0, [Math]::Min(80, $errorResponse.error.Length)))..."
335
+
336
+ if ($errorResponse.error -like "*already exists*" -or $errorResponse.error -like "*déjà*") {
337
+ Write-Success "Correct error message (name already in use)"
338
+ $PassedTests++
339
+ } else {
340
+ Write-ErrorUnexpected "Unexpected error message"
341
+ $FailedTests++
342
+ }
343
+ }
344
+ } else {
345
+ Write-Info "Test skipped: no existing notebook (cannot test duplicate)"
346
+ Write-Info "To test this case: add at least one notebook"
347
+ }
348
+
349
+ # =============================================================================
350
+ # TEST 8: POST /notebooks - Inaccessible notebook (invalid ID)
351
+ # =============================================================================
352
+ Write-TestHeader "POST /notebooks - Error: inaccessible notebook" 8 $TotalTests
353
+
354
+ Write-Info "This test may take 15-30 seconds (live validation)..."
355
+
356
+ try {
357
+ $body = @{
358
+ url = "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-invalid-id-xyz"
359
+ name = "Test Inaccessible Notebook XYZ"
360
+ description = "Test of a notebook that doesn't exist"
361
+ topics = @("test")
362
+ } | ConvertTo-Json
363
+
364
+ $result = Invoke-RestMethod -Uri "$BaseUrl/notebooks" -Method Post -Body $body -ContentType "application/json" -TimeoutSec 60
365
+
366
+ # If no HTTP exception, check success: false
367
+ if ($result.success -eq $false) {
368
+ Write-ErrorExpected "$($result.error.Substring(0, [Math]::Min(100, $result.error.Length)))..."
369
+
370
+ if ($result.error -like "*Invalid*" -or $result.error -like "*inaccessible*" -or $result.error -like "*not found*") {
371
+ Write-Success "Correct error message (inaccessible notebook)"
372
+ $PassedTests++
373
+ } else {
374
+ Write-ErrorUnexpected "Unexpected error message"
375
+ $FailedTests++
376
+ }
377
+ } else {
378
+ Write-ErrorUnexpected "Should return success: false"
379
+ $FailedTests++
380
+ }
381
+ } catch {
382
+ # HTTP exception (500, etc.)
383
+ $errorResponse = $_.ErrorDetails.Message | ConvertFrom-Json
384
+ Write-ErrorExpected "$($errorResponse.error.Substring(0, [Math]::Min(100, $errorResponse.error.Length)))..."
385
+
386
+ if ($errorResponse.error -like "*Invalid*" -or $errorResponse.error -like "*inaccessible*" -or $errorResponse.error -like "*not found*") {
387
+ Write-Success "Correct error message (inaccessible notebook)"
388
+ $PassedTests++
389
+ } else {
390
+ Write-ErrorUnexpected "Unexpected error message"
391
+ $FailedTests++
392
+ }
393
+ }
394
+
395
+ # =============================================================================
396
+ # TEST 9: GET /notebooks/:id - Non-existent notebook
397
+ # =============================================================================
398
+ Write-TestHeader "GET /notebooks/:id - Error: non-existent notebook" 9 $TotalTests
399
+
400
+ try {
401
+ $result = Invoke-RestMethod -Uri "$BaseUrl/notebooks/notebook-nonexistent-xyz-999"
402
+
403
+ # If no HTTP exception, check success: false
404
+ if ($result.success -eq $false) {
405
+ Write-ErrorExpected "$($result.error)"
406
+
407
+ if ($result.error -like "*not found*" -or $result.error -like "*introuvable*") {
408
+ Write-Success "Correct error message (notebook not found)"
409
+ $PassedTests++
410
+ } else {
411
+ Write-ErrorUnexpected "Unexpected error message"
412
+ $FailedTests++
413
+ }
414
+ } else {
415
+ Write-ErrorUnexpected "Should return success: false"
416
+ $FailedTests++
417
+ }
418
+ } catch {
419
+ # HTTP exception (500, etc.)
420
+ $errorResponse = $_.ErrorDetails.Message | ConvertFrom-Json
421
+ Write-ErrorExpected "$($errorResponse.error)"
422
+
423
+ if ($errorResponse.error -like "*not found*" -or $errorResponse.error -like "*introuvable*") {
424
+ Write-Success "Correct error message (notebook not found)"
425
+ $PassedTests++
426
+ } else {
427
+ Write-ErrorUnexpected "Unexpected error message"
428
+ $FailedTests++
429
+ }
430
+ }
431
+
432
+ # =============================================================================
433
+ # TEST 10: DELETE /notebooks/:id - Non-existent notebook
434
+ # =============================================================================
435
+ Write-TestHeader "DELETE /notebooks/:id - Error: non-existent notebook" 10 $TotalTests
436
+
437
+ try {
438
+ $result = Invoke-RestMethod -Uri "$BaseUrl/notebooks/notebook-nonexistent-xyz-999" -Method Delete
439
+
440
+ # If no HTTP exception, check success: false
441
+ if ($result.success -eq $false) {
442
+ Write-ErrorExpected "$($result.error)"
443
+
444
+ if ($result.error -like "*not found*" -or $result.error -like "*introuvable*") {
445
+ Write-Success "Correct error message (notebook not found)"
446
+ $PassedTests++
447
+ } else {
448
+ Write-ErrorUnexpected "Unexpected error message"
449
+ $FailedTests++
450
+ }
451
+ } else {
452
+ Write-ErrorUnexpected "Should return success: false"
453
+ $FailedTests++
454
+ }
455
+ } catch {
456
+ # HTTP exception (500, etc.)
457
+ $errorResponse = $_.ErrorDetails.Message | ConvertFrom-Json
458
+ Write-ErrorExpected "$($errorResponse.error)"
459
+
460
+ if ($errorResponse.error -like "*not found*" -or $errorResponse.error -like "*introuvable*") {
461
+ Write-Success "Correct error message (notebook not found)"
462
+ $PassedTests++
463
+ } else {
464
+ Write-ErrorUnexpected "Unexpected error message"
465
+ $FailedTests++
466
+ }
467
+ }
468
+
469
+ # =============================================================================
470
+ # TEST 11: PUT /notebooks/:id/activate - Non-existent notebook
471
+ # =============================================================================
472
+ Write-TestHeader "PUT /notebooks/:id/activate - Error: non-existent notebook" 11 $TotalTests
473
+
474
+ try {
475
+ $result = Invoke-RestMethod -Uri "$BaseUrl/notebooks/notebook-nonexistent-xyz-999/activate" -Method Put
476
+
477
+ # If no HTTP exception, check success: false
478
+ if ($result.success -eq $false) {
479
+ Write-ErrorExpected "$($result.error)"
480
+
481
+ if ($result.error -like "*not found*" -or $result.error -like "*introuvable*") {
482
+ Write-Success "Correct error message (notebook not found)"
483
+ $PassedTests++
484
+ } else {
485
+ Write-ErrorUnexpected "Unexpected error message"
486
+ $FailedTests++
487
+ }
488
+ } else {
489
+ Write-ErrorUnexpected "Should return success: false"
490
+ $FailedTests++
491
+ }
492
+ } catch {
493
+ # HTTP exception (500, etc.)
494
+ $errorResponse = $_.ErrorDetails.Message | ConvertFrom-Json
495
+ Write-ErrorExpected "$($errorResponse.error)"
496
+
497
+ if ($errorResponse.error -like "*not found*" -or $errorResponse.error -like "*introuvable*") {
498
+ Write-Success "Correct error message (notebook not found)"
499
+ $PassedTests++
500
+ } else {
501
+ Write-ErrorUnexpected "Unexpected error message"
502
+ $FailedTests++
503
+ }
504
+ }
505
+
506
+ # =============================================================================
507
+ # TEST 12: DELETE /sessions/:id - Non-existent session
508
+ # =============================================================================
509
+ Write-TestHeader "DELETE /sessions/:id - Error: non-existent session" 12 $TotalTests
510
+
511
+ try {
512
+ $result = Invoke-RestMethod -Uri "$BaseUrl/sessions/session-nonexistent-xyz-999" -Method Delete
513
+
514
+ # If no HTTP exception, check success: false
515
+ if ($result.success -eq $false) {
516
+ Write-ErrorExpected "$($result.error)"
517
+
518
+ if ($result.error -like "*not found*" -or $result.error -like "*introuvable*") {
519
+ Write-Success "Correct error message (session not found)"
520
+ $PassedTests++
521
+ } else {
522
+ Write-ErrorUnexpected "Unexpected error message"
523
+ $FailedTests++
524
+ }
525
+ } else {
526
+ Write-ErrorUnexpected "Should return success: false"
527
+ $FailedTests++
528
+ }
529
+ } catch {
530
+ # HTTP exception (500, etc.)
531
+ $errorResponse = $_.ErrorDetails.Message | ConvertFrom-Json
532
+ Write-ErrorExpected "$($errorResponse.error)"
533
+
534
+ if ($errorResponse.error -like "*not found*" -or $errorResponse.error -like "*introuvable*") {
535
+ Write-Success "Correct error message (session not found)"
536
+ $PassedTests++
537
+ } else {
538
+ Write-ErrorUnexpected "Unexpected error message"
539
+ $FailedTests++
540
+ }
541
+ }
542
+
543
+ # =============================================================================
544
+ # FINAL SUMMARY
545
+ # =============================================================================
546
+ Write-Host "`n" -NoNewline
547
+ Write-Host "╔════════════════════════════════════════════════════════╗" -ForegroundColor Magenta
548
+ Write-Host "║ ║" -ForegroundColor Magenta
549
+ Write-Host "║ ERROR TEST SUMMARY ║" -ForegroundColor Cyan
550
+ Write-Host "║ ║" -ForegroundColor Magenta
551
+ Write-Host "╚════════════════════════════════════════════════════════╝" -ForegroundColor Magenta
552
+ Write-Host ""
553
+
554
+ $TotalExecuted = $PassedTests + $FailedTests
555
+ $SuccessRate = if ($TotalExecuted -gt 0) { [math]::Round(($PassedTests / $TotalExecuted) * 100, 1) } else { 0 }
556
+
557
+ Write-Host "Total tests: $TotalTests" -ForegroundColor White
558
+ Write-Host "Tests passed: " -NoNewline -ForegroundColor White
559
+ Write-Host "$PassedTests" -ForegroundColor Green
560
+ Write-Host "Tests failed: " -NoNewline -ForegroundColor White
561
+ Write-Host "$FailedTests" -ForegroundColor $(if($FailedTests -gt 0){"Red"}else{"Green"})
562
+ Write-Host "Tests skipped: " -NoNewline -ForegroundColor White
563
+ Write-Host "$($TotalTests - $TotalExecuted)" -ForegroundColor Yellow
564
+ Write-Host "Success rate: " -NoNewline -ForegroundColor White
565
+ Write-Host "$SuccessRate%" -ForegroundColor $(if($SuccessRate -eq 100){"Green"}elseif($SuccessRate -ge 80){"Yellow"}else{"Red"})
566
+
567
+ Write-Host ""
568
+
569
+ if ($FailedTests -eq 0) {
570
+ Write-Host "════════════════════════════════════════════════════════" -ForegroundColor Green
571
+ Write-Host " ✓ ALL ERROR CASES ARE HANDLED CORRECTLY!" -ForegroundColor Green
572
+ Write-Host "════════════════════════════════════════════════════════" -ForegroundColor Green
573
+ exit 0
574
+ } else {
575
+ Write-Host "════════════════════════════════════════════════════════" -ForegroundColor Yellow
576
+ Write-Host " ⚠ SOME ERROR CASES ARE NOT HANDLED" -ForegroundColor Yellow
577
+ Write-Host "════════════════════════════════════════════════════════" -ForegroundColor Yellow
578
+ Write-Host ""
579
+ Write-Host "See details above to identify the issues." -ForegroundColor Yellow
580
+ exit 1
581
+ }