Skip to content

feat(PINE-31): E2E-005 vector browsing tests - #29

Merged
stepandel merged 6 commits into
masterfrom
feat/pine-31-vector-browsing-tests
Feb 4, 2026
Merged

feat(PINE-31): E2E-005 vector browsing tests#29
stepandel merged 6 commits into
masterfrom
feat/pine-31-vector-browsing-tests

Conversation

@stepandel

@stepandel stepandel commented Feb 3, 2026

Copy link
Copy Markdown
Owner

Closes PINE-31

Summary

Adds comprehensive E2E tests for vector browsing functionality (E2E-005).

Tests Added

  • Pinecone vector table display and pagination
  • Vector detail panel with metadata
  • Search/filter functionality
  • Qdrant and Weaviate vector browsing (skipped without live backends)

Test Results

  • 8 passed (UI tests without backend)
  • 73 skipped (require live backends)

Summary by CodeRabbit

  • Tests
    • Added comprehensive end-to-end test suites covering connection flows, index/collection management, namespace operations, and vector browsing functionality.
    • Implemented multi-provider test coverage for Pinecone, Qdrant, and Weaviate (Qdrant and Weaviate tests marked for future completion).
    • Enhanced E2E testing documentation with detailed setup and execution instructions.

stepandel and others added 5 commits February 3, 2026 11:44
Implemented comprehensive E2E tests for connection management:

Pinecone Tests:
- Connection modal display and form validation
- Required field validation
- Error handling for invalid API keys
- Successful connection with valid credentials
- Collections/indexes display after connection
- Disconnect functionality
- Reconnection after disconnect
- Profile saving and loading
- Unreachable URL error handling

Qdrant/Weaviate Tests:
- Skeleton tests with test.skip() and TODO comments
- Will be enabled when adapter system is integrated

Test Features:
- Uses Docker test containers from docker-compose.test.yml
- Leverages existing e2e/electron.setup.ts helpers
- Auto-skips tests requiring real API keys when not available
- Comprehensive error path testing

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add comprehensive E2E tests for index/collection operations:
- List indexes/collections after connecting
- View index/collection stats (vector count, dimensions)
- Create new collection with provider-specific settings
- Delete collection (with confirmation)
- Refresh collection list

Implementation:
- 8 active Pinecone tests covering full index lifecycle
- 13 skipped Qdrant/Weaviate tests with TODO comments
- Uses existing e2e/ infrastructure from PINE-28
- Tests use window.electronAPI for IPC communication
- Proper test isolation with unique profile/index names

Test coverage:
✅ Pinecone: List, stats, create, delete, refresh, error handling
🔲 Qdrant: Pending adapter integration
🔲 Weaviate: Pending adapter integration

References: PINE-29
Related: IndexesPanel.tsx, IndexConfigView.tsx

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
11 comprehensive tests for Pinecone namespace functionality:
- List namespaces in an index
- Select namespace to view vectors
- Clone namespace with progress tracking
- Duplicate namespace with progress events
- Namespace stats display
- Cancellation support
- Error handling

Test features:
- Progress event validation
- Resource cleanup
- Non-destructive (uses temp resources)
- Requires PINECONE_API_KEY for execution

Closes PINE-30
@claude

claude Bot commented Feb 3, 2026

Copy link
Copy Markdown

Code review

I found one issue that needs to be addressed:

Logic Error in Qdrant Adapter: Validation-Implementation Mismatch for Sparse Vector Queries

Location: electron/adapters/qdrant-adapter.ts lines 285-317

The queryVectors method accepts sparseVector as a valid query parameter in its validation check:

if (!params.vector && !params.sparseVector && !params.id) {
throw new Error('Query requires vector, sparseVector, or id')
}

However, the implementation only handles two cases:

  1. params.id queries (using the recommend API)
  2. Dense vector queries (using params.vector!)

if (params.id) {
// Query by ID - use recommend API
const queryId = params.id
const response = await this.withRetry(() =>
this.client!.recommend(params.collectionName, {
positive: [queryId],
limit: params.topK || 10,
with_payload: params.includeMetadata ?? true,
with_vector: params.includeValues ?? false,
filter: params.filter ? this.translateQdrantFilter(params.filter) : undefined,
})
)
results = response
} else {
// Query by vector
const response = await this.withRetry(() =>
this.client!.search(params.collectionName, {
vector: params.vector!,
limit: params.topK || 10,
with_payload: params.includeMetadata ?? true,
with_vector: params.includeValues ?? false,
filter: params.filter ? this.translateQdrantFilter(params.filter) : undefined,
})
)
results = response
}

Issue: If a caller provides only sparseVector without vector or id, the code will:

  1. Pass the validation check (since sparseVector is truthy)
  2. Fall into the else branch at line 306
  3. Use params.vector! which is undefined, causing a runtime error

Suggested Fix:

Either add support for sparse vector queries or remove sparseVector from the validation. If Qdrant supports sparse vectors, add an explicit branch:

if (params.id) {
  // Query by ID
  // ...
} else if (params.sparseVector) {
  // Query by sparse vector
  // Implement using Qdrant's sparse vector API
} else {
  // Query by dense vector
  const response = await this.withRetry(() =>
    this.client!.search(params.collectionName, {
      vector: params.vector!,
      // ...
    })
  )
}

If sparse vectors are not supported yet, update the validation:

if (!params.vector && !params.id) {
  throw new Error('Query requires vector or id')
}

@coderabbitai

coderabbitai Bot commented Feb 4, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This pull request adds comprehensive end-to-end test suites for the Electron app, covering connection flows, index/collection management, namespace operations, and vector browsing. Four new test files totaling 2,274 lines introduce extensive test coverage primarily for Pinecone with scaffolding for Qdrant and Weaviate providers, using Playwright and IPC-based interactions.

Changes

Cohort / File(s) Summary
E2E Test Suites
e2e/connection-flow.spec.ts, e2e/index-collection-management.spec.ts, e2e/namespace-operations.spec.ts, e2e/vector-browsing.spec.ts
Four new Playwright test files introducing 21–22 test cases each for testing Electron app functionality across connection flows, index management, namespace operations, and vector browsing. Tests use window.electronAPI for IPC interactions, conditional execution based on real API keys, and provider-specific scaffolding for Pinecone, Qdrant, and Weaviate.
E2E Documentation
E2E_TESTING.md
Updated documentation describing new test suites, coverage details, environment setup, and execution instructions for the E2E test infrastructure.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~80 minutes

Possibly related PRs

  • stepandel/pinecone-explorer#25: Modifies Playwright E2E testing infrastructure and setup utilities (playwright config, e2e helpers, E2E_TESTING.md documentation).

Poem

🐰 Test suites bloom like carrots in spring,
Connection flows and vectors take wing,
Pinecone, Qdrant, Weaviate too,
E2E coverage shiny and new! 🎯✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: adding E2E-005 vector browsing tests and implementing the PINE-31 feature ticket.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/pine-31-vector-browsing-tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@e2e/connection-flow.spec.ts`:
- Around line 70-80: Replace the test API key string that triggered the secret
scanner in the profile object to a clearly non-secret placeholder (e.g.,
"INVALID_API_KEY_PLACEHOLDER") or add a gitleaks allowlist comment next to the
usage; update the code that constructs the test profile (the profile variable
and its apiKey field, and any related profileId/test-invalid string) so the
value cannot match common API-key regexes while preserving test semantics for
the connection failure scenario.

In `@e2e/namespace-operations.spec.ts`:
- Around line 155-198: Add teardown to remove test-created namespaces/vectors
after the spec: after creating testNamespace and testVectors (the code that
calls (window as any).electronAPI.pinecone.createVector and checks
getIndexStats), add an afterAll (or run cleanup immediately after assertions)
that calls the Pinecone deletion API to remove the data; use the same bridge
methods used to create/read data (e.g., (window as
any).electronAPI.pinecone.deleteVector or deleteVectors or deleteNamespace) with
testProfileId/testIndexName and the testNamespace to delete either each
testVectors[].id or the whole namespace, and apply the same cleanup for the
other tests referenced at 283-321 so repeated runs do not accumulate data.

In `@e2e/vector-browsing.spec.ts`:
- Around line 55-112: The tests currently reuse an existing namespace found via
listIndexes/getIndexStats which leads to flaky metadata types; change the logic
in this block to always create and use a dedicated deterministic namespace (set
testNamespace to a unique name like `test-vectors-${Date.now()}-${uuid}`),
always populate it with a known set of vectors (the testVectors creation and
createVector calls), skip the branch that accepts an existing namespace (remove
the early selection from stats.namespaces), and ensure teardown removes the
vectors/namespace after tests complete; update references to testNamespace and
testIndexName so all assertions use only this created namespace and keep
createVector/getIndexStats/listIndexes usage intact.
- Around line 483-486: The forEach callbacks are implicitly returning the result
of Set.add because they use expression bodies; change both forEach callbacks to
use block bodies with explicit statements (e.g., replace the arrow expressions
in vectors.forEach(...) and the nested Object.keys(v.metadata).forEach(...) so
they use { ... } and call metadataKeys.add(key); without returning anything) and
apply the same change to the other occurrence that also iterates and adds to
metadataKeys (the second vectors.forEach/... Object.keys(...).forEach instance).
🧹 Nitpick comments (1)
e2e/index-collection-management.spec.ts (1)

23-27: Make the stateful Pinecone tests serial and replace fixed sleeps with polling.

These tests share testIndexName and depend on remote index readiness; fixed waitForTimeout calls are prone to flakiness. Prefer test.describe.serial and expect.poll on list/index stats to wait deterministically.

♻️ Example adjustment for serial mode + polling
-test.describe('Pinecone Index Management', () => {
+test.describe.serial('Pinecone Index Management', () => {
   // ...
-  await page.waitForTimeout(5000)
+  await expect.poll(async () => {
+    const indexes = await page.evaluate(async (id) =>
+      (window as any).electronAPI.pinecone.listIndexes(id),
+      testProfileId
+    )
+    return indexes.some((idx: any) => idx.name === testIndexName)
+  }, { timeout: 20000 }).toBeTruthy()
-  await page.waitForTimeout(3000)
+  await expect.poll(async () => {
+    const indexes = await page.evaluate(async (id) =>
+      (window as any).electronAPI.pinecone.listIndexes(id),
+      testProfileId
+    )
+    return indexes.every((idx: any) => idx.name !== testIndexName)
+  }, { timeout: 20000 }).toBeTruthy()

Also applies to: 185-188, 217-226

Comment on lines +70 to +80
// Create a profile with invalid API key and test connection via IPC
const profileId = `test-invalid-${Date.now()}`

const connectionFailed = await page.evaluate(async (id) => {
const profile = {
id,
name: 'Invalid Key Test',
provider: 'pinecone' as const,
apiKey: 'invalid-api-key-12345',
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid secret-scan false positives for the dummy API key.

Line 78 contains a string that matches generic API key patterns and was flagged by Gitleaks; this can fail CI despite being a test value. Use a clearly non-secret placeholder and/or an allowlist comment to prevent false positives.

🛡️ Suggested tweak to avoid secret-scanner hits
-          apiKey: 'invalid-api-key-12345',
+          apiKey: 'invalid-api-key-for-tests', // gitleaks:allow
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Create a profile with invalid API key and test connection via IPC
const profileId = `test-invalid-${Date.now()}`
const connectionFailed = await page.evaluate(async (id) => {
const profile = {
id,
name: 'Invalid Key Test',
provider: 'pinecone' as const,
apiKey: 'invalid-api-key-12345',
}
// Create a profile with invalid API key and test connection via IPC
const profileId = `test-invalid-${Date.now()}`
const connectionFailed = await page.evaluate(async (id) => {
const profile = {
id,
name: 'Invalid Key Test',
provider: 'pinecone' as const,
apiKey: 'invalid-api-key-for-tests', // gitleaks:allow
}
🧰 Tools
🪛 Gitleaks (8.30.0)

[high] 78-78: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 Prompt for AI Agents
In `@e2e/connection-flow.spec.ts` around lines 70 - 80, Replace the test API key
string that triggered the secret scanner in the profile object to a clearly
non-secret placeholder (e.g., "INVALID_API_KEY_PLACEHOLDER") or add a gitleaks
allowlist comment next to the usage; update the code that constructs the test
profile (the profile variable and its apiKey field, and any related
profileId/test-invalid string) so the value cannot match common API-key regexes
while preserving test semantics for the connection failure scenario.

Comment on lines +155 to +198
// Create test namespace with a few vectors
const testNamespace = `test-ns-${Date.now()}`
const testVectors = [
{
id: `test-vec-1`,
values: Array(dimension).fill(0).map(() => Math.random()),
metadata: { test: true, index: 1 },
},
{
id: `test-vec-2`,
values: Array(dimension).fill(0).map(() => Math.random()),
metadata: { test: true, index: 2 },
},
]

// Upsert vectors to create namespace
await page.evaluate(async ({ id, indexName, namespace, vectors }) => {
for (const vector of vectors) {
await (window as any).electronAPI.pinecone.createVector(id, {
indexName,
namespace,
id: vector.id,
values: vector.values,
metadata: vector.metadata,
})
}
}, {
id: testProfileId,
indexName: testIndexName,
namespace: testNamespace,
vectors: testVectors,
})

// Wait for vectors to be indexed
await page.waitForTimeout(3000)

// Verify namespace was created by checking stats
const stats = await page.evaluate(async ({ id, name }) => {
return await (window as any).electronAPI.pinecone.getIndexStats(id, name)
}, { id: testProfileId, name: testIndexName })

expect(stats.namespaces[testNamespace]).toBeDefined()
expect(stats.namespaces[testNamespace].vectorCount).toBe(testVectors.length)
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Clean up test-created namespaces/vectors to avoid data buildup.

The suite creates namespaces and clones them but never deletes test vectors; repeated runs can pollute real indexes and incur cost. Please add cleanup (e.g., delete all vectors in test namespaces) in afterAll or immediately after validation.

Also applies to: 283-321

🤖 Prompt for AI Agents
In `@e2e/namespace-operations.spec.ts` around lines 155 - 198, Add teardown to
remove test-created namespaces/vectors after the spec: after creating
testNamespace and testVectors (the code that calls (window as
any).electronAPI.pinecone.createVector and checks getIndexStats), add an
afterAll (or run cleanup immediately after assertions) that calls the Pinecone
deletion API to remove the data; use the same bridge methods used to create/read
data (e.g., (window as any).electronAPI.pinecone.deleteVector or deleteVectors
or deleteNamespace) with testProfileId/testIndexName and the testNamespace to
delete either each testVectors[].id or the whole namespace, and apply the same
cleanup for the other tests referenced at 283-321 so repeated runs do not
accumulate data.

Comment on lines +55 to +112
// Get the first available index to use for testing
const indexes = await page.evaluate(async (id) => {
return await (window as any).electronAPI.pinecone.listIndexes(id)
}, testProfileId)

if (indexes.length > 0) {
testIndexName = indexes[0].name

// Get a namespace with vectors for testing
const stats = await page.evaluate(async ({ id, name }) => {
return await (window as any).electronAPI.pinecone.getIndexStats(id, name)
}, { id: testProfileId, name: testIndexName })

// Find first namespace with vectors
for (const [name, data] of Object.entries(stats.namespaces as Record<string, any>)) {
if (data.vectorCount > 0) {
testNamespace = name
break
}
}

// If no namespace has vectors, create test vectors
if (!testNamespace) {
testNamespace = `test-vectors-${Date.now()}`
const dimension = indexes[0].dimension || 384

// Create a few test vectors
const testVectors = Array.from({ length: 5 }, (_, i) => ({
id: `test-vector-${i}`,
values: Array(dimension).fill(0).map(() => Math.random()),
metadata: {
test: true,
index: i,
description: `Test vector ${i}`,
category: i % 2 === 0 ? 'even' : 'odd',
},
}))

for (const vector of testVectors) {
await page.evaluate(async ({ id, indexName, namespace, vector }) => {
await (window as any).electronAPI.pinecone.createVector(id, {
indexName,
namespace,
id: vector.id,
values: vector.values,
metadata: vector.metadata,
})
}, {
id: testProfileId,
indexName: testIndexName,
namespace: testNamespace,
vector,
})
}

// Wait for vectors to be indexed
await page.waitForTimeout(3000)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make vector-browsing tests deterministic by always using a dedicated test namespace.

Right now, the suite reuses the first existing namespace with vectors, which can include arbitrary metadata schemas and types. This makes assertions (e.g., metadata type checks) flaky across environments. Consider always creating a unique test namespace with known vectors and using that for all assertions (and clean it up afterward).

🤖 Prompt for AI Agents
In `@e2e/vector-browsing.spec.ts` around lines 55 - 112, The tests currently reuse
an existing namespace found via listIndexes/getIndexStats which leads to flaky
metadata types; change the logic in this block to always create and use a
dedicated deterministic namespace (set testNamespace to a unique name like
`test-vectors-${Date.now()}-${uuid}`), always populate it with a known set of
vectors (the testVectors creation and createVector calls), skip the branch that
accepts an existing namespace (remove the early selection from
stats.namespaces), and ensure teardown removes the vectors/namespace after tests
complete; update references to testNamespace and testIndexName so all assertions
use only this created namespace and keep createVector/getIndexStats/listIndexes
usage intact.

Comment on lines +483 to +486
vectors.forEach((v: any) => {
if (v.metadata) {
Object.keys(v.metadata).forEach(key => metadataKeys.add(key))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix Biome lint errors: forEach callbacks must not return values.

Both callbacks currently return the Set.add result implicitly; use block bodies to avoid returning a value.

🛠️ Suggested fix for the forEach callbacks
-          Object.keys(v.metadata).forEach(key => metadataKeys.add(key))
+          Object.keys(v.metadata).forEach(key => {
+            metadataKeys.add(key)
+          })
-        keys.forEach(k => allKeys.add(k))
+        keys.forEach(k => {
+          allKeys.add(k)
+        })

Also applies to: 601-605

🧰 Tools
🪛 Biome (2.3.13)

[error] 485-485: This callback passed to forEach() iterable method should not return a value.

Either remove this return or remove the returned value.

(lint/suspicious/useIterableCallbackReturn)

🤖 Prompt for AI Agents
In `@e2e/vector-browsing.spec.ts` around lines 483 - 486, The forEach callbacks
are implicitly returning the result of Set.add because they use expression
bodies; change both forEach callbacks to use block bodies with explicit
statements (e.g., replace the arrow expressions in vectors.forEach(...) and the
nested Object.keys(v.metadata).forEach(...) so they use { ... } and call
metadataKeys.add(key); without returning anything) and apply the same change to
the other occurrence that also iterates and adds to metadataKeys (the second
vectors.forEach/... Object.keys(...).forEach instance).

@stepandel
stepandel merged commit 7f6b7b4 into master Feb 4, 2026
7 checks passed
@stepandel
stepandel deleted the feat/pine-31-vector-browsing-tests branch February 4, 2026 22:15
stepandel added a commit that referenced this pull request Feb 4, 2026
- Fix index creation timeout: use polling (90s) instead of fixed 5s wait
- Add gitleaks:allow comments to prevent false positives on test API keys
- Index creation now properly waits for status.ready=true

Addresses review comments from PRs #27, #29
stepandel added a commit that referenced this pull request Feb 4, 2026
- Fix index creation timeout: use polling (90s) instead of fixed 5s wait
- Add gitleaks:allow comments to prevent false positives on test API keys
- Index creation now properly waits for status.ready=true

Addresses review comments from PRs #27, #29

Co-authored-by: Stepan Arsentjev <stepandel@users.noreply.github.com>
stepandel added a commit that referenced this pull request Feb 4, 2026
* fix: address E2E test review issues

- Fix index creation timeout: use polling (90s) instead of fixed 5s wait
- Add gitleaks:allow comments to prevent false positives on test API keys
- Index creation now properly waits for status.ready=true

Addresses review comments from PRs #27, #29

* fix: address remaining E2E review issues

- Add teardown in namespace-operations.spec.ts to delete test-created namespaces/vectors
- Change vector-browsing.spec.ts to create dedicated test namespace with known metadata instead of reusing existing namespace
- Fix forEach callbacks in vector-browsing.spec.ts to use explicit block bodies instead of implicit returns
- Use test.describe.serial for stateful index create/delete tests in index-collection-management.spec.ts
- Replace fixed sleeps with polling in index-collection-management.spec.ts

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Stepan Arsentjev <stepandel@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant