Skip to content

Conversation

@FabianSanchezD
Copy link
Contributor

@FabianSanchezD FabianSanchezD commented Jan 22, 2026

StellarRent Logo

Pull Request | StellarRent

📝 Summary

Some Tests were failing because the Supabase mock was not implemented correctly, created a supabase mock file and updated tests to use it. All tests that use this mock are passing.

🔗 Related Issues

Closes #197

🔄 Changes Made

Fixed Supabase mock configuration across all test files to resolve "undefined is not an object (evaluating 'supabase.auth.getUser')" errors.

  • ✅ Fixed "undefined is not an object (evaluating 'supabase.auth.getUser')" errors
  • ✅ All three target test files now have consistent, working Supabase mocks
  • ✅ Tests converted to use Bun framework consistently
  • ✅ Improved test maintainability with shared mock utility

🖼️ Current Output

image Wallet Auth Tests image Booking Tests image Sync Service Test

🧪 Testing

Screenshots above.

✅ Testing Checklist

  • Unit tests added/modified
  • Integration tests performed
  • Manual tests executed
  • All tests pass in CI/CD

⚠️ Potential Risks

Most tests outside of the ones done for this PR still fail, so it is good to take a look at them.

🚀 Next Steps & Improvements

This change lays a solid foundation for further optimizations. Some areas that could benefit from future improvements include:

  • 🔹 Performance optimization
  • 🔹 Increased test coverage
  • 🔹 Potential user experience enhancements

💬 Comments

Thanks for reviewing this PR! If you see that I made more files than required, it is because I make the Supabase Mock separated and updated files that needed changes.

Summary by CodeRabbit

  • Tests

    • Centralized and standardized mock infrastructure for Supabase and blockchain RPCs, with new in-memory mock helpers and setup to simplify and stabilize tests.
    • Test imports and initialization reordered to ensure mocks are applied consistently across suites.
  • Chores

    • Backend now initializes a real Supabase client and enforces a required service-role key via environment validation.
    • Updated SDK RPC import path and removed unused test utilities.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

📝 Walkthrough

Walkthrough

Centralized Bun-compatible Supabase mocks and test setup were added and applied before SUT imports; several integration and unit tests were updated to use the centralized mock. The Supabase config now initializes a real client and requires SUPABASE_SERVICE_ROLE_KEY. The Soroban RPC import path in sync.service.ts was updated.

Changes

Cohort / File(s) Summary
Soroban RPC import
apps/backend/src/services/sync.service.ts
Updated import path from @stellar/stellar-sdk/lib/rpc@stellar/stellar-sdk/rpc; removed unused exec/promisify plumbing.
Supabase client config
apps/backend/src/config/supabase.ts
Replaced test/mock conditional with a real createClient<Database> export; added required SUPABASE_SERVICE_ROLE_KEY validation and explicit auth/db options.
Global test setup
apps/backend/tests/setup.ts, apps/backend/src/tests/booking.test.ts, apps/backend/src/tests/sync.service.test.ts
Added centralized test setup import order (setup before SUT), environment variables for tests, and reuse of global Supabase mock via setupSupabaseMock.
Supabase mock plumbing
apps/backend/tests/mocks/supabase.mock.setup.ts, apps/backend/tests/mocks/supabase.mock.ts, apps/backend/tests/mocks/supabase.mock.chain.ts, apps/backend/tests/mocks/supabase.mock.data.ts
New Bun-compatible Supabase mock: in-memory data store, chainable query helpers, basic auth (getUser/signIn/signUp), CRUD semantics, and a setup helper that registers module mocks for multiple module paths.
Tests updated to centralized mocks
apps/backend/src/tests/sync.service.test.ts, apps/backend/tests/integration/booking.test.ts, apps/backend/tests/integration/wallet-auth.test.ts
Tests refactored to import global setup, use setupSupabaseMock/shared supabase, convert to Bun-style mocks, adjust localized messages and contract ID env usage, and remove per-test mock wiring.
Test manifest/harness
package.json (manifest change)
Minor test-related manifest adjustment (single-line change).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰
I hopped through mocks and patched each trace,
Built a burrowed DB in memory’s space.
RPCs aligned, contracts set to play,
Tests march tidy on their happy way.
Hop—another green tick for today.

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: Supabase Mock Configuration in Tests' directly addresses the main change: centralizing and fixing Supabase mock configuration across test files to resolve test failures.
Linked Issues check ✅ Passed The PR addresses all primary objectives from issue #197: creates consistent Supabase mocks across wallet-auth, booking, and sync.service tests; refactors tests to use centralized mock setup; and establishes a shared mock infrastructure to resolve authentication test failures.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing Supabase mock configuration: new mock utilities, updated imports in target tests, and refactored test setup. Import path updates for Stellar SDK are incidental dependency changes.

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

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@FabianSanchezD
Copy link
Contributor Author

Let me know if any changes are required, happy to help!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/backend/tests/integration/booking.test.ts (1)

75-97: Mock may not take effect for pre-built app.

The app is built in beforeAll() with the original getBooking controller. Calling mock.module() in individual tests won't affect the already-imported controller that's bound to the Express app.

Notice how the 200 OK test (lines 223-228) correctly handles this by re-importing the controller after setting up the mock and creating a new Express app. The same pattern should be applied to these error scenario tests, or the app should be rebuilt after each mock setup.

💡 Suggested approach

Either:

  1. Apply the same pattern as the 200 OK test (re-import and rebuild app after mock)
  2. Or move mock setup to beforeAll and use per-test mock return values
🤖 Fix all issues with AI agents
In `@apps/backend/src/tests/sync.service.test.ts`:
- Around line 145-158: The test names claim event processing and error handling
but only start/stop the service (syncService.start(), syncService.getStatus(),
syncService.stop()); either rename the two it(...) descriptions to something
like "should start and stop service during event processing" and "should start
and stop service when event processing errors occur", or expand the tests to
assert real behavior: after syncService.start() emit or call the actual event
handler (e.g., syncService.processEvent or the event emitter used by the
service) with a mock "booking created" payload and assert the expected handler
was invoked and side-effects occurred, and for the error test stub the handler
to throw/reject and assert the service stays alive, logs the error, and
recovers/continues (or stops) as expected; keep using syncService.start(),
syncService.getStatus(), and syncService.stop() while adding appropriate
spies/mocks and assertions for handler invocation and error logging.

In `@apps/backend/tests/integration/booking.test.ts`:
- Around line 48-49: Remove the duplicated assertion that checks the HTTP
status: there are two identical lines calling expect(res.status).toBe(400); —
keep a single expect(res.status).toBe(400); and delete the redundant duplicate
(both reference the same res variable in the failing test).
🧹 Nitpick comments (6)
apps/backend/tests/mocks/supabase.mock.ts (3)

143-143: Unused variable originalEq.

The variable originalEq is declared but never used. This appears to be leftover from a refactoring. Consider removing it.

🧹 Suggested fix
     update: mock(() => {
       const updateChain = createMockChain(tableName);
-      const originalEq = updateChain.eq;
       updateChain.eq = mock((column: string, value: any) => {

165-165: Unused variable originalEq.

Same issue as above - originalEq is declared but never used in the delete() method.

🧹 Suggested fix
     delete: mock(() => {
       const deleteChain = createMockChain(tableName);
-      const originalEq = deleteChain.eq;
       deleteChain.eq = mock((column: string, value: any) => {

49-78: Filter matching is incomplete for in and match operators.

The single() and then() methods only handle eq, gt, and lt operators in the filter matching logic, but the chain supports in and match filters (lines 35-44). If tests use .in() queries, the filtering will silently be skipped.

Consider adding support for the in operator:

💡 Example fix for the filter matching
             if (filter.operator === 'lt' && new Date(item[filter.column]) >= new Date(filter.value)) {
               matches = false;
               break;
             }
+            if (filter.operator === 'in' && !filter.values?.includes(item[filter.column])) {
+              matches = false;
+              break;
+            }
           }
apps/backend/tests/setup.ts (1)

9-44: Consider extracting duplicated MockServer class.

The MockServer class is duplicated for both @stellar/stellar-sdk/rpc and @stellar/stellar-sdk/lib/rpc paths. While this works, extracting it to a shared constant would reduce duplication:

💡 Optional refactor
+class MockServer {
+  constructor(_url: string) {}
+  async getLatestLedger() {
+    return Promise.resolve({ sequence: 1000 });
+  }
+  async getContractEvents() {
+    return Promise.resolve({ events: [] });
+  }
+}
+
 mock.module('@stellar/stellar-sdk/rpc', () => {
-  class MockServer {
-    constructor(_url: string) {}
-    async getLatestLedger() {
-      return Promise.resolve({ sequence: 1000 });
-    }
-    async getContractEvents() {
-      return Promise.resolve({ events: [] });
-    }
-  }
   return {
     Server: MockServer,
     default: { Server: MockServer },
   };
 });

 mock.module('@stellar/stellar-sdk/lib/rpc', () => {
-  class MockServer {
-    constructor(_url: string) {}
-    async getLatestLedger() {
-      return Promise.resolve({ sequence: 1000 });
-    }
-    async getContractEvents() {
-      return Promise.resolve({ events: [] });
-    }
-  }
   return {
     Server: MockServer,
     default: { Server: MockServer },
   };
 });
apps/backend/src/tests/sync.service.test.ts (1)

226-274: Duplicate test cases detected.

The tests at lines 226-274 (should use custom polling interval... and should fallback to default polling interval...) are exact duplicates of the tests at lines 66-114 within the describe('Initialization', ...) block. Consider removing the duplicates.

🧹 Suggested fix
   });
-
-  it('should use custom polling interval from environment variable', () => {
-    // ... duplicate test code
-  });
-
-  it('should fallback to default polling interval for invalid environment value', () => {
-    // ... duplicate test code
-  });
 });
apps/backend/tests/integration/booking.test.ts (1)

56-72: Inconsistent language in error messages across the codebase.

The auth middleware returns Spanish error messages for 401/403 responses ("Token no proporcionado", "Token inválido o expirado"), while the error middleware and other validators use English ("Invalid token", "Token expired", "Validation error"). The tests accurately reflect the current implementation, but this mixed-language approach should be addressed:

  • Standardize on a single language for all error messages
  • Or implement a proper i18n solution if multi-language support is intended

Copy link
Contributor

@respp respp left a comment

Choose a reason for hiding this comment

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

Your code is very close to being merged. I’ve left some corrections above; once you address those and follow the coderabbit suggestions, we should be all set

@FabianSanchezD
Copy link
Contributor Author

FabianSanchezD commented Jan 26, 2026

Hi, just saw the review, working on this ASAP!

@FabianSanchezD
Copy link
Contributor Author

Fixed all requested changes and merge conflicts. LMK if any more changes are needed!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
apps/backend/tests/integration/booking.test.ts (1)

70-92: Mock applied after controller import won't take effect.

The controller getBooking is imported at line 13, before mock.module() is called in this test. In Bun, mock.module() must be called before the module being mocked is imported. Since booking.controller already imported booking.service, this mock won't affect the controller's behavior.

Compare with the 200 test (lines 218-222) which correctly re-imports the controller after applying the mock. Apply the same pattern here.

🐛 Suggested fix pattern (apply to all error tests)
   it('403: user is neither booker nor host', async () => {
     // Mock getBookingById to throw access denied error
     mock.module('../../src/services/booking.service', () => ({
       ...bookingServiceModule,
       getBookingById: mock(async () => {
         throw new Error('Access denied');
       }),
     }));

+    // Re-import controller to get the mocked service
+    const { getBooking: getBookingMocked } = await import('../../src/controllers/booking.controller');
+    const testApp = express();
+    testApp.use(express.json());
+    testApp.get('/bookings/:bookingId', authenticateToken, getBookingMocked);
+
-    const res = await request(app)
+    const res = await request(testApp)
       .get(`/bookings/${testBookingId}`)
       .set('Authorization', validToken);
apps/backend/src/tests/sync.service.test.ts (2)

62-86: Duplicate tests: "should use custom polling interval from environment variable".

The test at lines 62-86 (inside describe('Initialization')) and the test at lines 299-322 (at the top level) are identical. Remove one of them.

🧹 Suggested fix

Remove lines 299-322 (the duplicate at the top level):

-  it('should use custom polling interval from environment variable', () => {
-    // Save original environment variables
-    const originalPollingInterval = process.env.SYNC_POLL_INTERVAL;
-    const originalRpcUrl = process.env.SOROBAN_RPC_URL;
-    const originalContractId = process.env.SOROBAN_CONTRACT_ID;
-    const originalNetworkPassphrase = process.env.SOROBAN_NETWORK_PASSPHRASE;
-
-    try {
-      // Set custom polling interval
-      process.env.SYNC_POLL_INTERVAL = '10000';
-      process.env.SOROBAN_RPC_URL = 'https://test-rpc.stellar.org';
-      process.env.SOROBAN_CONTRACT_ID = 'CB3ILSDNHL6TWZYZJAS4L27GLHNAGW4ISW6YXIBHGHL4QYI4JPLP6W3E';
-      process.env.SOROBAN_NETWORK_PASSPHRASE = 'Test SDF Network ; September 2015';
-
-      const customSyncService = new SyncService();
-      expect(customSyncService.getPollingIntervalMs()).toBe(10000);
-    } finally {
-      // Restore original environment variables
-      process.env.SYNC_POLL_INTERVAL = originalPollingInterval;
-      process.env.SOROBAN_RPC_URL = originalRpcUrl;
-      process.env.SOROBAN_CONTRACT_ID = originalContractId;
-      process.env.SOROBAN_NETWORK_PASSPHRASE = originalNetworkPassphrase;
-    }
-  });

Also applies to: 299-322


88-112: Duplicate tests: "should fallback to default polling interval".

The test at lines 88-112 (inside describe('Initialization')) and the test at lines 324-347 (at the top level) are identical. Remove one of them.

🧹 Suggested fix

Remove lines 324-347 (the duplicate at the top level):

-  it('should fallback to default polling interval for invalid environment value', () => {
-    // Save original environment variables
-    const originalPollingInterval = process.env.SYNC_POLL_INTERVAL;
-    const originalRpcUrl = process.env.SOROBAN_RPC_URL;
-    const originalContractId = process.env.SOROBAN_CONTRACT_ID;
-    const originalNetworkPassphrase = process.env.SOROBAN_NETWORK_PASSPHRASE;
-
-    try {
-      // Set invalid polling interval
-      process.env.SYNC_POLL_INTERVAL = 'invalid';
-      process.env.SOROBAN_RPC_URL = 'https://test-rpc.stellar.org';
-      process.env.SOROBAN_CONTRACT_ID = 'CB3ILSDNHL6TWZYZJAS4L27GLHNAGW4ISW6YXIBHGHL4QYI4JPLP6W3E';
-      process.env.SOROBAN_NETWORK_PASSPHRASE = 'Test SDF Network ; September 2015';
-
-      const fallbackSyncService = new SyncService();
-      expect(fallbackSyncService.getPollingIntervalMs()).toBe(5000); // Default fallback
-    } finally {
-      // Restore original environment variables
-      process.env.SYNC_POLL_INTERVAL = originalPollingInterval;
-      process.env.SOROBAN_RPC_URL = originalRpcUrl;
-      process.env.SOROBAN_CONTRACT_ID = originalContractId;
-      process.env.SOROBAN_NETWORK_PASSPHRASE = originalNetworkPassphrase;
-    }
-  });

Also applies to: 324-347

🤖 Fix all issues with AI agents
In `@apps/backend/tests/mocks/supabase.mock.chain.ts`:
- Around line 5-37: findMatchingRecords currently only handles 'eq', 'gt', and
'lt', ignores 'in' and 'match' filters accumulated in _filters, and always
treats gt/lt as date comparisons; update findMatchingRecords to evaluate 'in'
(check item[filter.column] is one of filter.values) and 'match' (perform
substring/regex match against item[filter.column] using filter.value), and
change gt/lt logic to detect numeric vs date comparison (e.g., if both item[*]
and filter.value are numbers compare numerically, otherwise parse as dates) so
numeric queries work correctly; keep references to the function name
findMatchingRecords and the filter properties (operator, column, value, values)
when implementing these cases.

In `@apps/backend/tests/mocks/supabase.mock.ts`:
- Around line 13-14: The mockFrom function creates a new Map for unknown
tableName but never saves it, so inserts into unknown tables are lost; update
mockFrom to check if mockDataStore[tableName] is missing and if so assign a new
Map back into mockDataStore (or call mockDataStore.set(tableName, new Map()) if
mockDataStore is a Map) before returning tableData so subsequent inserts
persist; reference the mockFrom function and mockDataStore when making this
change.

In `@apps/backend/tests/setup.ts`:
- Line 52: The placeholder secret assigned in Object.defineProperty(process.env,
'STELLAR_SECRET_KEY', ...) is not a valid 56-character base32 Stellar secret
(must start with 'S'); replace the hardcoded invalid string with a properly
formatted test secret (e.g., a known testnet secret) or generate a valid secret
at test setup time (for example using Stellar SDK's
Keypair.random()/Keypair.fromSecret() and assign its secret) and set
process.env.STELLAR_SECRET_KEY to that value so any SDK validation succeeds.
🧹 Nitpick comments (11)
apps/backend/tests/mocks/supabase.mock.chain.ts (2)

76-79: Inconsistent async behavior in then().

The then() method invokes the callback synchronously and returns its result directly, whereas single() returns Promise.resolve(...). This inconsistency could cause subtle timing issues in tests that depend on Promise-like behavior.

Proposed fix for consistent Promise behavior
     then: mock((callback: any) => {
       const results = findMatchingRecords(tableName, mockDataStore, chain._filters || []);
-      return callback({ data: results, error: null });
+      return Promise.resolve(callback({ data: results, error: null }));
     }),

75-75: maybeSingle() ignores accumulated filters.

Unlike single(), maybeSingle() always returns { data: null, error: null } without evaluating the filter chain. If tests rely on maybeSingle() returning actual data, they will fail silently.

Proposed fix
-    maybeSingle: mock(() => Promise.resolve({ data: null, error: null })),
+    maybeSingle: mock(() => {
+      const matches = findMatchingRecords(tableName, mockDataStore, chain._filters || []);
+      return Promise.resolve({ data: matches[0] ?? null, error: null });
+    }),
apps/backend/src/tests/booking.test.ts (1)

59-68: Redundant local mock conflicts with centralized setup.

The test file imports the centralized setup (line 2) which registers the Supabase mock, but then creates and assigns a separate local mock via Object.assign(supabase, createMockSupabaseMethods()) (line 91). This pattern:

  1. May not fully override the centralized mock since Object.assign only assigns own enumerable properties
  2. Creates maintenance burden by duplicating mock logic
  3. Defeats the purpose of the centralized mock infrastructure introduced in this PR

Consider either removing the local mock and relying on the centralized mock, or pre-seeding the centralized mock's data store in beforeEach.

Also applies to: 89-94

apps/backend/tests/mocks/supabase.mock.ts (1)

43-50: update() and delete() only operate on id or public_key columns.

The filter evaluation is hardcoded to only match against id or public_key columns. Queries like .update(...).eq('status', 'pending') will accumulate the filter but never apply the update/delete to matching records.

This may be intentional to keep the mock simple, but could cause test failures if tests expect full filter support.

Proposed fix to support arbitrary column filters
           // When update().eq() is called, apply the update
-          if (column === 'id' || column === 'public_key') {
-            for (const item of tableData.values()) {
-              if (item[column] === value) {
-                Object.assign(item, { updated_at: new Date().toISOString() });
-              }
+          for (const item of tableData.values()) {
+            if (item[column] === value) {
+              Object.assign(item, { updated_at: new Date().toISOString() });
             }
           }

Also applies to: 63-70

apps/backend/tests/setup.ts (2)

10-45: Consider extracting the duplicated MockServer class.

The MockServer class is defined identically in both mock.module calls (lines 11-21 and 30-40). Extract it once before the mocks to reduce duplication.

♻️ Suggested refactor
+// Shared MockServer for Stellar SDK RPC mocks
+class MockServer {
+  constructor(_url: string) {
+    // Mock server constructor
+  }
+  async getLatestLedger() {
+    return Promise.resolve({ sequence: 1000 });
+  }
+  async getContractEvents() {
+    return Promise.resolve({ events: [] });
+  }
+}
+
 // Mock Stellar SDK RPC module for tests BEFORE any imports
 // This prevents module resolution errors when sync.service.ts is imported
 mock.module('@stellar/stellar-sdk/rpc', () => {
-  class MockServer {
-    constructor(_url: string) {
-      // Mock server constructor
-    }
-    async getLatestLedger() {
-      return Promise.resolve({ sequence: 1000 });
-    }
-    async getContractEvents() {
-      return Promise.resolve({ events: [] });
-    }
-  }
   return {
     Server: MockServer,
     default: { Server: MockServer },
   };
 });

 // Also mock the lib/rpc path that sync.service.ts was trying to use
 mock.module('@stellar/stellar-sdk/lib/rpc', () => {
-  class MockServer {
-    constructor(_url: string) {
-      // Mock server constructor
-    }
-    async getLatestLedger() {
-      return Promise.resolve({ sequence: 1000 });
-    }
-    async getContractEvents() {
-      return Promise.resolve({ events: [] });
-    }
-  }
   return {
     Server: MockServer,
     default: { Server: MockServer },
   };
 });

83-89: Redundant setupSupabaseMock() calls may cause overhead.

setupSupabaseMock() is called both at module load time (line 84) and in beforeEach (line 88). The beforeEach call is intended to restore mocks if mock.restore() is called, but this means every test re-registers multiple module paths even when unnecessary.

Consider tracking whether restoration is needed or documenting why this overhead is acceptable for test stability.

apps/backend/tests/integration/booking.test.ts (1)

118-162: Single test case asserts two different scenarios sequentially.

This test applies two different mocks (Property not found, then Host user not found) and makes two requests, but the second mock.module() call at line 142 won't replace the first mock correctly without re-importing the controller (same issue as above). Additionally, combining two distinct scenarios in one test reduces clarity and makes failures harder to diagnose.

Consider splitting into two separate test cases.

apps/backend/src/tests/sync.service.test.ts (4)

234-267: Manual operations tests lack meaningful assertions.

These tests ("should trigger manual sync", "should process blockchain events during manual sync", "should handle blockchain errors during manual sync") all have identical structure and only assert that isRunning is true. They don't actually verify:

  • That manual sync was triggered
  • That blockchain events were processed
  • That errors were handled

Consider adding assertions that verify the expected behavior, such as checking lastSyncTime changes, event counts, or mock call verification.


283-296: Error handling tests don't test error scenarios.

Tests "should handle network errors gracefully" and "should handle database errors gracefully" only start/stop the service and check isRunning. They don't simulate any network or database errors.

Consider injecting faults (e.g., mocking RPC or Supabase to throw) and verifying the service handles them gracefully (logs errors, continues running, increments failedEvents, etc.).


198-205: Directly patching private handler is brittle.

Mutating serviceWithHandlers.handleBookingCreated directly couples the test to implementation details. If the method name or structure changes, this test breaks.

Consider mocking at the module level (as done for booking.service in the other test file) or using dependency injection patterns.


145-180: Type assertions for mock internals are fragile.

The pattern supabase.from as unknown as { mock?: { calls: Array<[string]> } } assumes a specific mock structure that may not be guaranteed by the createSupabaseMock implementation. If the mock changes, this will fail silently or throw unexpected errors.

Consider exposing a proper API from the mock (e.g., getMockCalls()) or using Bun's built-in mock introspection if available.

Comment on lines +5 to +37
const findMatchingRecords = (
tableName: string,
mockDataStore: MockDataStore,
filters: Array<{ column: string; value?: any; values?: any[]; operator: string }>
) => {
const tableData = mockDataStore[tableName] || new Map();
if (filters.length === 0) {
return [];
}

const results: any[] = [];
for (const item of tableData.values()) {
let matches = true;
for (const filter of filters) {
if (filter.operator === 'eq' && item[filter.column] !== filter.value) {
matches = false;
break;
}
if (filter.operator === 'gt' && new Date(item[filter.column]) <= new Date(filter.value)) {
matches = false;
break;
}
if (filter.operator === 'lt' && new Date(item[filter.column]) >= new Date(filter.value)) {
matches = false;
break;
}
}
if (matches) {
results.push(item);
}
}
return results;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Incomplete filter operator implementations.

The in and match operators are accumulated in _filters (lines 57-66) but findMatchingRecords only evaluates eq, gt, and lt. Queries using .in() or .match() will silently ignore those filters.

Additionally, gt and lt comparisons always parse values as dates (lines 23-30), which will produce incorrect results for numeric comparisons.

Proposed fix to add missing operator evaluations
       if (filter.operator === 'lt' && new Date(item[filter.column]) >= new Date(filter.value)) {
         matches = false;
         break;
       }
+      if (filter.operator === 'in' && !filter.values?.includes(item[filter.column])) {
+        matches = false;
+        break;
+      }
+      if (filter.operator === 'match' && item[filter.column] !== filter.value) {
+        matches = false;
+        break;
+      }
     }
📝 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
const findMatchingRecords = (
tableName: string,
mockDataStore: MockDataStore,
filters: Array<{ column: string; value?: any; values?: any[]; operator: string }>
) => {
const tableData = mockDataStore[tableName] || new Map();
if (filters.length === 0) {
return [];
}
const results: any[] = [];
for (const item of tableData.values()) {
let matches = true;
for (const filter of filters) {
if (filter.operator === 'eq' && item[filter.column] !== filter.value) {
matches = false;
break;
}
if (filter.operator === 'gt' && new Date(item[filter.column]) <= new Date(filter.value)) {
matches = false;
break;
}
if (filter.operator === 'lt' && new Date(item[filter.column]) >= new Date(filter.value)) {
matches = false;
break;
}
}
if (matches) {
results.push(item);
}
}
return results;
};
const findMatchingRecords = (
tableName: string,
mockDataStore: MockDataStore,
filters: Array<{ column: string; value?: any; values?: any[]; operator: string }>
) => {
const tableData = mockDataStore[tableName] || new Map();
if (filters.length === 0) {
return [];
}
const results: any[] = [];
for (const item of tableData.values()) {
let matches = true;
for (const filter of filters) {
if (filter.operator === 'eq' && item[filter.column] !== filter.value) {
matches = false;
break;
}
if (filter.operator === 'gt' && new Date(item[filter.column]) <= new Date(filter.value)) {
matches = false;
break;
}
if (filter.operator === 'lt' && new Date(item[filter.column]) >= new Date(filter.value)) {
matches = false;
break;
}
if (filter.operator === 'in' && !filter.values?.includes(item[filter.column])) {
matches = false;
break;
}
if (filter.operator === 'match' && item[filter.column] !== filter.value) {
matches = false;
break;
}
}
if (matches) {
results.push(item);
}
}
return results;
};
🤖 Prompt for AI Agents
In `@apps/backend/tests/mocks/supabase.mock.chain.ts` around lines 5 - 37,
findMatchingRecords currently only handles 'eq', 'gt', and 'lt', ignores 'in'
and 'match' filters accumulated in _filters, and always treats gt/lt as date
comparisons; update findMatchingRecords to evaluate 'in' (check
item[filter.column] is one of filter.values) and 'match' (perform
substring/regex match against item[filter.column] using filter.value), and
change gt/lt logic to detect numeric vs date comparison (e.g., if both item[*]
and filter.value are numbers compare numerically, otherwise parse as dates) so
numeric queries work correctly; keep references to the function name
findMatchingRecords and the filter properties (operator, column, value, values)
when implementing these cases.

Comment on lines +13 to +14
const mockFrom = mock((tableName: string) => {
const tableData = mockDataStore[tableName] || new Map();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Data inserted into unknown tables is silently lost.

When tableName is not in mockDataStore, a new Map() is created but never stored back. Any data inserted into an unknown table will be discarded since tableData is a local variable.

Proposed fix
   const mockFrom = mock((tableName: string) => {
-    const tableData = mockDataStore[tableName] || new Map();
+    if (!mockDataStore[tableName]) {
+      mockDataStore[tableName] = new Map();
+    }
+    const tableData = mockDataStore[tableName];
📝 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
const mockFrom = mock((tableName: string) => {
const tableData = mockDataStore[tableName] || new Map();
const mockFrom = mock((tableName: string) => {
if (!mockDataStore[tableName]) {
mockDataStore[tableName] = new Map();
}
const tableData = mockDataStore[tableName];
🤖 Prompt for AI Agents
In `@apps/backend/tests/mocks/supabase.mock.ts` around lines 13 - 14, The mockFrom
function creates a new Map for unknown tableName but never saves it, so inserts
into unknown tables are lost; update mockFrom to check if
mockDataStore[tableName] is missing and if so assign a new Map back into
mockDataStore (or call mockDataStore.set(tableName, new Map()) if mockDataStore
is a Map) before returning tableData so subsequent inserts persist; reference
the mockFrom function and mockDataStore when making this change.

Object.defineProperty(process.env, 'JWT_SECRET', { value: 'test-secret-key', writable: true });
Object.defineProperty(process.env, 'STELLAR_NETWORK', { value: 'testnet', writable: true });
Object.defineProperty(process.env, 'USE_MOCK', { value: 'true', writable: true });
Object.defineProperty(process.env, 'STELLAR_SECRET_KEY', { value: 'SBTESTXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', writable: true });
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Invalid Stellar secret key format.

The placeholder SBTESTXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX is not a valid Stellar secret key format. Stellar secret keys are 56 characters starting with 'S' and are base32-encoded. While this is a test value, an invalid format could cause unexpected failures if the SDK validates key format during instantiation.

Consider using a properly formatted test key or a known testnet key format.

🤖 Prompt for AI Agents
In `@apps/backend/tests/setup.ts` at line 52, The placeholder secret assigned in
Object.defineProperty(process.env, 'STELLAR_SECRET_KEY', ...) is not a valid
56-character base32 Stellar secret (must start with 'S'); replace the hardcoded
invalid string with a properly formatted test secret (e.g., a known testnet
secret) or generate a valid secret at test setup time (for example using Stellar
SDK's Keypair.random()/Keypair.fromSecret() and assign its secret) and set
process.env.STELLAR_SECRET_KEY to that value so any SDK validation succeeds.

@FabianSanchezD
Copy link
Contributor Author

@respp should I go ahead and fix what coderabbit suggests?

@respp respp merged commit 27a900b into Stellar-Rent:main Jan 26, 2026
1 check passed
@coderabbitai coderabbitai bot mentioned this pull request Jan 26, 2026
4 tasks
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.

Fix Supabase Mock Configuration in Tests

2 participants