Skip to content

Commit 70ec539

Browse files
authored
Merge pull request #15 from supabase-community/feat/error
feat: Add support for triggering error for PostgREST methods.
2 parents 998e32b + b199dc0 commit 70ec539

File tree

3 files changed

+697
-96
lines changed

3 files changed

+697
-96
lines changed

README.md

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,142 @@ void main() {
139139
}
140140
```
141141

142+
### Mocking Errors
143+
144+
You can simulate error scenarios by configuring an error trigger callback. This is useful for testing how your application handles various error conditions:
145+
146+
```dart
147+
void main() {
148+
late final SupabaseClient mockSupabase;
149+
late final MockSupabaseHttpClient mockHttpClient;
150+
151+
setUp(() {
152+
// Configure error trigger
153+
mockHttpClient = MockSupabaseHttpClient(
154+
postgrestExceptionTrigger: (schema, table, data, type) {
155+
// Simulate unique constraint violation on email
156+
if (table == 'users' && type == RequestType.insert) {
157+
throw PostgrestException(
158+
message: 'duplicate key value violates unique constraint "users_email_key"',
159+
code: '23505', // Postgres unique violation code
160+
);
161+
}
162+
163+
// Simulate permission error for certain operations
164+
if (table == 'private_data' && type == RequestType.select) {
165+
throw PostgrestException(
166+
message: 'permission denied for table private_data',
167+
code: '42501', // Postgres permission denied code
168+
);
169+
}
170+
},
171+
);
172+
173+
mockSupabase = SupabaseClient(
174+
'https://mock.supabase.co',
175+
'fakeAnonKey',
176+
httpClient: mockHttpClient,
177+
);
178+
});
179+
180+
test('handles duplicate email error', () async {
181+
expect(
182+
() => mockSupabase.from('users').insert({
183+
'email': '[email protected]',
184+
'name': 'Test User'
185+
}),
186+
throwsA(isA<PostgrestException>()),
187+
);
188+
});
189+
}
190+
```
191+
192+
### RPC Functions
193+
194+
You can mock Remote Procedure Call (RPC) functions by registering them with the mock client:
195+
196+
```dart
197+
void main() {
198+
late final SupabaseClient mockSupabase;
199+
late final MockSupabaseHttpClient mockHttpClient;
200+
201+
setUp(() {
202+
mockHttpClient = MockSupabaseHttpClient();
203+
204+
// Register mock RPC functions
205+
mockHttpClient.registerRpcFunction(
206+
'get_user_status',
207+
(params, tables) => {'status': 'active', 'last_seen': '2024-03-20'},
208+
);
209+
210+
mockHttpClient.registerRpcFunction(
211+
'calculate_total',
212+
(params, tables) {
213+
final amount = params['amount'] as num;
214+
final tax = params['tax_rate'] as num;
215+
return {
216+
'total': amount + (amount * tax),
217+
'tax_amount': amount * tax,
218+
};
219+
},
220+
);
221+
222+
mockSupabase = SupabaseClient(
223+
'https://mock.supabase.co',
224+
'fakeAnonKey',
225+
httpClient: mockHttpClient,
226+
);
227+
});
228+
229+
test('calls RPC function with parameters', () async {
230+
final result = await mockSupabase.rpc(
231+
'calculate_total',
232+
params: {'amount': 100, 'tax_rate': 0.1},
233+
);
234+
235+
expect(result, {
236+
'total': 110.0,
237+
'tax_amount': 10.0,
238+
});
239+
});
240+
241+
test('mocks complex RPC function using database state', () async {
242+
// Insert some test data
243+
await mockSupabase.from('orders').insert([
244+
{'id': 1, 'user_id': 123, 'amount': 100},
245+
{'id': 2, 'user_id': 123, 'amount': 200},
246+
]);
247+
248+
// Register RPC that uses the mock database state
249+
mockHttpClient.registerRpcFunction(
250+
'get_user_total_orders',
251+
(params, tables) {
252+
final userId = params['user_id'];
253+
final orders = tables['public.orders'] as List<Map<String, dynamic>>;
254+
255+
final userOrders = orders.where((order) => order['user_id'] == userId);
256+
final total = userOrders.fold<num>(
257+
0,
258+
(sum, order) => sum + (order['amount'] as num),
259+
);
260+
261+
return {'total_orders': userOrders.length, 'total_amount': total};
262+
},
263+
);
264+
265+
final result = await mockSupabase.rpc(
266+
'get_user_total_orders',
267+
params: {'user_id': 123},
268+
);
269+
270+
expect(result, {
271+
'total_orders': 2,
272+
'total_amount': 300,
273+
});
274+
});
275+
}
276+
```
277+
142278
## Current Limitations
143279

144280
- The mock Supabase client does not know the table schema. This means that it does not know if the inserted mock data is a referenced table data, or just a array/JSON object. This could potentially return more data than you construct a mock data with more than one referenced table.
@@ -154,7 +290,6 @@ void main() {
154290
- count and head requests are not supported.
155291
- aggregate functions are not supported.
156292
- Respect nullsFirst on ordering is not supported.
157-
- rpc support is not supported.
158293
- The errors thrown by the mock Supabase client is not the same as the actual Supabase client.
159294
- The mock Supabase client does not support auth, realtime, storage, or calling edge functions.
160295
- You can either mock those using libraries like [mockito](https://pub.dev/packages/mockito) or use the Supabase CLI to do a full integration testing. You could use our [GitHub actions](https://github.com/supabase/setup-cli) to do that.

0 commit comments

Comments
 (0)