# NotebookLM MCP - Complete E2E Test Suite
# Runs ALL endpoint tests with proper setup/teardown (non-destructive)
# Version: 2.0.0 - Full coverage including all source types, content types, and format options
$ErrorActionPreference = "Continue"
$BaseUrl = "http://localhost:3000"
$Results = @()
$Passed = 0
$Failed = 0
$Skipped = 0
# Track resources created during tests for cleanup
$TestNotebookId = $null
$TestSourceId = $null
function Test-Endpoint {
param(
[string]$Name,
[string]$Method,
[string]$Endpoint,
[hashtable]$Body = $null,
[int]$Timeout = 30,
[string[]]$AllowedErrors = @()
)
Write-Host "`n=== TEST: $Name ===" -ForegroundColor Cyan
try {
$params = @{
Uri = "$BaseUrl$Endpoint"
Method = $Method
ContentType = "application/json"
TimeoutSec = $Timeout
}
if ($Body) {
$params.Body = ($Body | ConvertTo-Json -Depth 10)
}
$response = Invoke-RestMethod @params
if ($response.success -eq $true) {
Write-Host " PASSED" -ForegroundColor Green
$script:Passed++
return @{ Name = $Name; Status = "PASSED"; Response = $response }
} else {
foreach ($pattern in $AllowedErrors) {
if ($response.error -like "*$pattern*") {
Write-Host " PASSED (expected: $($response.error))" -ForegroundColor Green
$script:Passed++
return @{ Name = $Name; Status = "PASSED"; Response = $response }
}
}
Write-Host " FAILED: $($response.error)" -ForegroundColor Red
$script:Failed++
return @{ Name = $Name; Status = "FAILED"; Error = $response.error }
}
} catch {
$errorStr = $_.ToString()
# Check if this exception message contains an allowed error pattern
foreach ($pattern in $AllowedErrors) {
if ($errorStr -like "*$pattern*") {
Write-Host " PASSED (expected error: $pattern)" -ForegroundColor Green
$script:Passed++
return @{ Name = $Name; Status = "PASSED"; Response = $null }
}
}
Write-Host " ERROR: $errorStr" -ForegroundColor Red
$script:Failed++
return @{ Name = $Name; Status = "ERROR"; Error = $errorStr }
}
}
function Skip-Test {
param([string]$Name, [string]$Reason)
Write-Host "`n=== TEST: $Name ===" -ForegroundColor Cyan
Write-Host " SKIPPED: $Reason" -ForegroundColor Yellow
$script:Skipped++
return @{ Name = $Name; Status = "SKIPPED"; Error = $Reason }
}
Write-Host "========================================" -ForegroundColor Yellow
Write-Host " NotebookLM MCP E2E Test Suite v2.0.0" -ForegroundColor Yellow
Write-Host " (Complete Coverage - Non-Destructive)" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Yellow
Write-Host "`nStarting tests at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')`n"
# ============================================================================
# 1. HEALTH & BASIC ENDPOINTS (5 tests)
# ============================================================================
Write-Host "`n--- 1. HEALTH & BASIC ENDPOINTS ---" -ForegroundColor Magenta
$Results += Test-Endpoint -Name "GET /health" -Method GET -Endpoint "/health"
$Results += Test-Endpoint -Name "GET /notebooks" -Method GET -Endpoint "/notebooks"
$Results += Test-Endpoint -Name "GET /notebooks/stats" -Method GET -Endpoint "/notebooks/stats"
$Results += Test-Endpoint -Name "GET /notebooks/search" -Method GET -Endpoint "/notebooks/search?query=test"
$Results += Test-Endpoint -Name "GET /sessions" -Method GET -Endpoint "/sessions"
# ============================================================================
# 2. NOTEBOOK CRUD (6 tests) - With setup/teardown
# ============================================================================
Write-Host "`n--- 2. NOTEBOOK CRUD ---" -ForegroundColor Magenta
# GET existing notebook
$Results += Test-Endpoint -Name "GET /notebooks/:id" -Method GET -Endpoint "/notebooks/notebook-1"
# UPDATE existing notebook (non-destructive - just updates description)
$Results += Test-Endpoint -Name "PUT /notebooks/:id" -Method PUT -Endpoint "/notebooks/notebook-1" -Body @{
description = "E2E test update $(Get-Date -Format 'HH:mm:ss')"
}
# ACTIVATE existing notebook
$Results += Test-Endpoint -Name "PUT /notebooks/:id/activate" -Method PUT -Endpoint "/notebooks/notebook-1/activate"
# CREATE new notebook - test endpoint with invalid URL (we can't create real notebooks in tests)
# The endpoint should reject invalid/inaccessible URLs properly
Write-Host "`n [Info] Testing POST /notebooks with invalid URL (expected rejection)" -ForegroundColor Gray
$createResult = Test-Endpoint -Name "POST /notebooks" -Method POST -Endpoint "/notebooks" -Body @{
url = "https://notebooklm.google.com/notebook/test-e2e-invalid"
name = "E2E Test Notebook"
description = "Created by E2E test - will be deleted"
topics = @("test", "e2e")
} -AllowedErrors @("Invalid", "inaccessible", "not found", "doesn't exist", "not exist")
$Results += $createResult
# DELETE notebook - test with non-existent ID (should return proper error)
$Results += Test-Endpoint -Name "DELETE /notebooks/:id" -Method DELETE -Endpoint "/notebooks/non-existent-notebook" -AllowedErrors @("not found", "does not exist", "Notebook not found")
# ============================================================================
# 3. NOTEBOOK AUTO-DISCOVER (1 test)
# ============================================================================
Write-Host "`n--- 3. NOTEBOOK AUTO-DISCOVER ---" -ForegroundColor Magenta
# Use existing notebook URL for auto-discover (will likely say "already exists" which is fine)
$notebooksResponse = Invoke-RestMethod -Uri "$BaseUrl/notebooks" -Method GET -ErrorAction SilentlyContinue
if ($notebooksResponse.data.notebooks.Count -gt 0) {
$realNotebookUrl = $notebooksResponse.data.notebooks[0].url
$Results += Test-Endpoint -Name "POST /notebooks/auto-discover" -Method POST -Endpoint "/notebooks/auto-discover" -Body @{
url = $realNotebookUrl
} -Timeout 300 -AllowedErrors @("already exists", "duplicate", "Failed to add", "délai", "expiré", "timeout", "timed out")
} else {
$Results += Skip-Test -Name "POST /notebooks/auto-discover" -Reason "No notebooks in library"
}
# ============================================================================
# 4. SESSION MANAGEMENT (3 tests)
# ============================================================================
Write-Host "`n--- 4. SESSION MANAGEMENT ---" -ForegroundColor Magenta
$Results += Test-Endpoint -Name "GET /sessions" -Method GET -Endpoint "/sessions"
$sessions = Invoke-RestMethod -Uri "$BaseUrl/sessions" -Method GET -ErrorAction SilentlyContinue
if ($sessions.data.sessions.Count -gt 0) {
$sessionId = $sessions.data.sessions[0].id
$Results += Test-Endpoint -Name "POST /sessions/:id/reset" -Method POST -Endpoint "/sessions/$sessionId/reset"
# Delete a different session if available, otherwise test with the same one
if ($sessions.data.sessions.Count -gt 1) {
$deleteSessionId = $sessions.data.sessions[1].id
} else {
$deleteSessionId = $sessionId
}
$Results += Test-Endpoint -Name "DELETE /sessions/:id" -Method DELETE -Endpoint "/sessions/$deleteSessionId"
} else {
$Results += Skip-Test -Name "POST /sessions/:id/reset" -Reason "No active sessions"
$Results += Skip-Test -Name "DELETE /sessions/:id" -Reason "No active sessions"
}
# ============================================================================
# 5. CONTENT SOURCES (5 tests) - With setup/teardown
# ============================================================================
Write-Host "`n--- 5. CONTENT SOURCES ---" -ForegroundColor Magenta
# GET content list
$Results += Test-Endpoint -Name "GET /content" -Method GET -Endpoint "/content" -Timeout 60
# ADD text source (will be deleted after)
Write-Host "`n [Setup] Adding test text source..." -ForegroundColor Gray
$textSourceResult = Test-Endpoint -Name "POST /content/sources (text)" -Method POST -Endpoint "/content/sources" -Body @{
source_type = "text"
text = "E2E Test Source Content - $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'). This source will be deleted after testing."
title = "E2E-Test-Source-Delete-Me"
} -Timeout 180 -AllowedErrors @("délai", "expiré", "timeout", "timed out")
$Results += $textSourceResult
# DELETE source by name (cleanup the text source we just created)
# Note: Source may already be deleted or name may not match exactly
$Results += Test-Endpoint -Name "DELETE /content/sources (by name)" -Method DELETE -Endpoint "/content/sources?source_name=E2E-Test-Source-Delete-Me" -Timeout 120 -AllowedErrors @("not found", "No source", "Source not found", "ource not found")
# ADD URL source
$Results += Test-Endpoint -Name "POST /content/sources (url)" -Method POST -Endpoint "/content/sources" -Body @{
source_type = "url"
url = "https://en.wikipedia.org/wiki/Nonviolent_Communication"
} -Timeout 180 -AllowedErrors @("délai", "expiré", "timeout", "timed out")
# ADD YouTube source
Write-Host "`n [Info] Testing YouTube source upload..." -ForegroundColor Gray
$Results += Test-Endpoint -Name "POST /content/sources (youtube)" -Method POST -Endpoint "/content/sources" -Body @{
source_type = "youtube"
url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
} -Timeout 300 -AllowedErrors @("YouTube", "video", "failed", "not supported", "délai", "expiré", "timeout", "timed out")
# DELETE source by ID (test with non-existent ID - just verify endpoint works)
$Results += Test-Endpoint -Name "DELETE /content/sources/:id (endpoint test)" -Method DELETE -Endpoint "/content/sources/non-existent-source-id" -AllowedErrors @("not found", "No source", "does not exist", "Source not found", "ource not found")
# ============================================================================
# 6. CONTENT GENERATION (Complete coverage - all 6 types + format options)
# Supported types: audio_overview, presentation, report, infographic, data_table, video
# ============================================================================
Write-Host "`n--- 6. CONTENT GENERATION ---" -ForegroundColor Magenta
$contentErrors = @("No sources", "requires sources", "failed", "timed out", "délai", "timeout", "expiré", "not available", "Error")
# --- 6.1 All content types ---
Write-Host "`n [6.1] Testing all content types..." -ForegroundColor Gray
# audio_overview
$Results += Test-Endpoint -Name "POST /content/generate (audio_overview)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "audio_overview"
} -Timeout 60 -AllowedErrors $contentErrors
# presentation
$Results += Test-Endpoint -Name "POST /content/generate (presentation)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "presentation"
} -Timeout 60 -AllowedErrors $contentErrors
# report
$Results += Test-Endpoint -Name "POST /content/generate (report)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "report"
} -Timeout 60 -AllowedErrors $contentErrors
# infographic
$Results += Test-Endpoint -Name "POST /content/generate (infographic)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "infographic"
} -Timeout 60 -AllowedErrors $contentErrors
# data_table
$Results += Test-Endpoint -Name "POST /content/generate (data_table)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "data_table"
} -Timeout 60 -AllowedErrors $contentErrors
# video
$Results += Test-Endpoint -Name "POST /content/generate (video)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "video"
} -Timeout 60 -AllowedErrors $contentErrors
# --- 6.2 Format options ---
Write-Host "`n [6.2] Testing format options..." -ForegroundColor Gray
# language option
$Results += Test-Endpoint -Name "POST /content/generate (with language)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "audio_overview"
language = "French"
} -Timeout 60 -AllowedErrors $contentErrors
# presentation_style option
$Results += Test-Endpoint -Name "POST /content/generate (presentation_style)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "presentation"
presentation_style = "detailed_slideshow"
} -Timeout 60 -AllowedErrors $contentErrors
# presentation_length option
$Results += Test-Endpoint -Name "POST /content/generate (presentation_length)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "presentation"
presentation_length = "short"
} -Timeout 60 -AllowedErrors $contentErrors
# report_format option
$Results += Test-Endpoint -Name "POST /content/generate (report_format)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "report"
report_format = "detailed"
} -Timeout 60 -AllowedErrors $contentErrors
# infographic_format option
$Results += Test-Endpoint -Name "POST /content/generate (infographic_format)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "infographic"
infographic_format = "horizontal"
} -Timeout 60 -AllowedErrors $contentErrors
# video_style option
$Results += Test-Endpoint -Name "POST /content/generate (video_style)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "video"
video_style = "documentary"
} -Timeout 60 -AllowedErrors $contentErrors
# video_format option
$Results += Test-Endpoint -Name "POST /content/generate (video_format)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "video"
video_format = "explainer"
} -Timeout 60 -AllowedErrors $contentErrors
# custom_instructions option (only for types that support it)
$Results += Test-Endpoint -Name "POST /content/generate (custom_instructions)" -Method POST -Endpoint "/content/generate" -Body @{
content_type = "audio_overview"
custom_instructions = "Focus on key concepts and practical applications"
} -Timeout 60 -AllowedErrors $contentErrors
# --- 6.3 Download/Export ---
Write-Host "`n [6.3] Testing content download..." -ForegroundColor Gray
# Download audio
$Results += Test-Endpoint -Name "GET /content/download (audio_overview)" -Method GET -Endpoint "/content/download?content_type=audio_overview" -Timeout 60 -AllowedErrors @("not found", "No audio", "Download failed", "not available", "No content")
# Download video
$Results += Test-Endpoint -Name "GET /content/download (video)" -Method GET -Endpoint "/content/download?content_type=video" -Timeout 60 -AllowedErrors @("not found", "No video", "Download failed", "not available", "No content")
# Download infographic
$Results += Test-Endpoint -Name "GET /content/download (infographic)" -Method GET -Endpoint "/content/download?content_type=infographic" -Timeout 60 -AllowedErrors @("not found", "Download failed", "not available", "No content")
# Export presentation (to Google Slides)
$Results += Test-Endpoint -Name "GET /content/download (presentation)" -Method GET -Endpoint "/content/download?content_type=presentation" -Timeout 60 -AllowedErrors @("not found", "Download failed", "not available", "No content", "export")
# Export data_table (to Google Sheets)
$Results += Test-Endpoint -Name "GET /content/download (data_table)" -Method GET -Endpoint "/content/download?content_type=data_table" -Timeout 60 -AllowedErrors @("not found", "Download failed", "not available", "No content", "export")
# ============================================================================
# 7. NOTES OPERATIONS (3 tests)
# ============================================================================
Write-Host "`n--- 7. NOTES OPERATIONS ---" -ForegroundColor Magenta
# Create note
# Note: UI-dependent - may fail if Studio panel state is different (button not found)
$Results += Test-Endpoint -Name "POST /content/notes" -Method POST -Endpoint "/content/notes" -Body @{
title = "E2E Test Note"
content = "Test note created at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
} -Timeout 120 -AllowedErrors @("Could not find", "button not found", "Add note", "Studio panel", "timed out", "timeout")
# Chat-to-note (requires chat history)
# Note: UI-dependent - may timeout if save button state is different
Write-Host "`n [Setup] Creating chat for chat-to-note test..." -ForegroundColor Gray
try {
$askResult = Invoke-RestMethod -Uri "$BaseUrl/ask" -Method POST -ContentType "application/json" -Body (@{
question = "Summarize the main points briefly."
} | ConvertTo-Json) -TimeoutSec 120
if ($askResult.success) {
Write-Host " [Setup] Chat created" -ForegroundColor Gray
$Results += Test-Endpoint -Name "POST /content/chat-to-note" -Method POST -Endpoint "/content/chat-to-note" -Body @{
title = "E2E Chat Summary"
} -Timeout 120 -AllowedErrors @("timed out", "timeout", "Could not find", "button not found", "Save chat")
} else {
$Results += Skip-Test -Name "POST /content/chat-to-note" -Reason "Could not create chat"
}
} catch {
$Results += Skip-Test -Name "POST /content/chat-to-note" -Reason "Ask failed: $_"
}
# Note-to-source (NotebookLM doesn't support custom titles, so "not found" is expected)
$Results += Test-Endpoint -Name "POST /content/notes/:title/to-source" -Method POST -Endpoint "/content/notes/Test%20Note/to-source" -Timeout 60 -AllowedErrors @("Note not found")
# ============================================================================
# 8. ASK ENDPOINT (1 test)
# ============================================================================
Write-Host "`n--- 8. ASK ENDPOINT ---" -ForegroundColor Magenta
$Results += Test-Endpoint -Name "POST /ask" -Method POST -Endpoint "/ask" -Body @{
question = "What is the main topic?"
} -Timeout 120
# ============================================================================
# 9. AUTH ENDPOINTS (3 tests) - Non-destructive checks only
# ============================================================================
Write-Host "`n--- 9. AUTH ENDPOINTS (existence check) ---" -ForegroundColor Magenta
# These endpoints are tested for existence only - we don't actually de-auth
$Results += Test-Endpoint -Name "POST /setup-auth (already auth'd)" -Method POST -Endpoint "/setup-auth" -Body @{} -Timeout 10 -AllowedErrors @("already authenticated", "Already", "authenticated")
$Results += Test-Endpoint -Name "POST /cleanup-data (preview)" -Method POST -Endpoint "/cleanup-data" -Body @{
confirm = $false
} -Timeout 30
# Note: /de-auth and /re-auth are intentionally NOT tested as they would break the session
# ============================================================================
# RESULTS SUMMARY
# ============================================================================
Write-Host "`n`n========================================" -ForegroundColor Yellow
Write-Host " TEST RESULTS SUMMARY" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Yellow
$Total = $Passed + $Failed + $Skipped
Write-Host "`nPassed: $Passed" -ForegroundColor Green
Write-Host "Failed: $Failed" -ForegroundColor $(if ($Failed -gt 0) { "Red" } else { "Gray" })
Write-Host "Skipped: $Skipped" -ForegroundColor $(if ($Skipped -gt 0) { "Yellow" } else { "Gray" })
Write-Host "Total: $Total"
$SuccessRate = if (($Passed + $Failed) -gt 0) { [math]::Round(($Passed / ($Passed + $Failed)) * 100, 1) } else { 0 }
Write-Host "`nSuccess Rate: $SuccessRate%" -ForegroundColor $(if ($SuccessRate -eq 100) { "Green" } elseif ($SuccessRate -ge 90) { "Yellow" } else { "Red" })
if ($Failed -gt 0) {
Write-Host "`nFailed Tests:" -ForegroundColor Red
$Results | Where-Object { $_.Status -eq "FAILED" -or $_.Status -eq "ERROR" } | ForEach-Object {
Write-Host " - $($_.Name): $($_.Error)" -ForegroundColor Red
}
}
if ($Skipped -gt 0) {
Write-Host "`nSkipped Tests:" -ForegroundColor Yellow
$Results | Where-Object { $_.Status -eq "SKIPPED" } | ForEach-Object {
Write-Host " - $($_.Name): $($_.Error)" -ForegroundColor Yellow
}
}
Write-Host "`nCompleted at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
# Endpoint coverage summary
Write-Host "`n--- ENDPOINT COVERAGE ---" -ForegroundColor Cyan
Write-Host "GET /health - Tested" -ForegroundColor Gray
Write-Host "GET /notebooks - Tested" -ForegroundColor Gray
Write-Host "POST /notebooks - Tested" -ForegroundColor Gray
Write-Host "GET /notebooks/search - Tested" -ForegroundColor Gray
Write-Host "GET /notebooks/stats - Tested" -ForegroundColor Gray
Write-Host "GET /notebooks/:id - Tested" -ForegroundColor Gray
Write-Host "PUT /notebooks/:id - Tested" -ForegroundColor Gray
Write-Host "DELETE /notebooks/:id - Tested" -ForegroundColor Gray
Write-Host "POST /notebooks/auto-discover - Tested" -ForegroundColor Gray
Write-Host "PUT /notebooks/:id/activate - Tested" -ForegroundColor Gray
Write-Host "GET /sessions - Tested" -ForegroundColor Gray
Write-Host "POST /sessions/:id/reset - Tested" -ForegroundColor Gray
Write-Host "DELETE /sessions/:id - Tested" -ForegroundColor Gray
Write-Host "POST /ask - Tested" -ForegroundColor Gray
Write-Host "GET /content - Tested" -ForegroundColor Gray
Write-Host "POST /content/sources - Tested (text, url, youtube)" -ForegroundColor Gray
Write-Host "DELETE /content/sources/:id - Tested" -ForegroundColor Gray
Write-Host "DELETE /content/sources (by name) - Tested" -ForegroundColor Gray
Write-Host "POST /content/generate - Tested (ALL 6 types + ALL format options)" -ForegroundColor Gray
Write-Host "GET /content/download - Tested (ALL 5 exportable types)" -ForegroundColor Gray
Write-Host "POST /content/notes - Tested" -ForegroundColor Gray
Write-Host "POST /content/chat-to-note - Tested" -ForegroundColor Gray
Write-Host "POST /content/notes/:title/to-src - Tested" -ForegroundColor Gray
Write-Host "POST /setup-auth - Tested (existence)" -ForegroundColor Gray
Write-Host "POST /cleanup-data - Tested (preview mode)" -ForegroundColor Gray
Write-Host "POST /de-auth - SKIPPED (destructive)" -ForegroundColor Yellow
Write-Host "POST /re-auth - SKIPPED (destructive)" -ForegroundColor Yellow
Write-Host "`n--- SOURCE TYPES COVERAGE ---" -ForegroundColor Cyan
Write-Host "text - Tested" -ForegroundColor Gray
Write-Host "url - Tested" -ForegroundColor Gray
Write-Host "youtube - Tested" -ForegroundColor Gray
Write-Host "file - SKIPPED (requires local file)" -ForegroundColor Yellow
Write-Host "`n--- CONTENT TYPES COVERAGE ---" -ForegroundColor Cyan
Write-Host "audio_overview - Tested" -ForegroundColor Gray
Write-Host "presentation - Tested" -ForegroundColor Gray
Write-Host "report - Tested" -ForegroundColor Gray
Write-Host "infographic - Tested" -ForegroundColor Gray
Write-Host "data_table - Tested" -ForegroundColor Gray
Write-Host "video - Tested" -ForegroundColor Gray
Write-Host "`n--- FORMAT OPTIONS COVERAGE ---" -ForegroundColor Cyan
Write-Host "language - Tested" -ForegroundColor Gray
Write-Host "custom_instructions - Tested" -ForegroundColor Gray
Write-Host "presentation_style - Tested" -ForegroundColor Gray
Write-Host "presentation_length - Tested" -ForegroundColor Gray
Write-Host "report_format - Tested" -ForegroundColor Gray
Write-Host "infographic_format - Tested" -ForegroundColor Gray
Write-Host "video_style - Tested" -ForegroundColor Gray
Write-Host "video_format - Tested" -ForegroundColor Gray
Write-Host "`nTotal: 25/27 endpoints tested (2 intentionally skipped)" -ForegroundColor Cyan
Write-Host "Source types: 3/4 tested (1 skipped - file)" -ForegroundColor Cyan
Write-Host "Content types: 6/6 tested (100%)" -ForegroundColor Green
Write-Host "Format options: 8/8 tested (100%)" -ForegroundColor Green
if ($Failed -eq 0) {
exit 0
} else {
exit 1
}