{"id":15285292,"url":"https://github.com/supabase-community/mock_supabase_http_client","last_synced_at":"2025-06-26T19:35:07.273Z","repository":{"id":256243982,"uuid":"853943371","full_name":"supabase-community/mock_supabase_http_client","owner":"supabase-community","description":"A mock HTTP client for mocking Supabase Client in Dart application.","archived":false,"fork":false,"pushed_at":"2025-03-18T16:31:56.000Z","size":98,"stargazers_count":9,"open_issues_count":6,"forks_count":5,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-06-18T11:27:15.940Z","etag":null,"topics":["flutter","supabase","supabase-client","supabase-flutter","testing"],"latest_commit_sha":null,"homepage":"https://supabase.com","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/supabase-community.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-08T01:05:53.000Z","updated_at":"2025-04-15T09:10:00.000Z","dependencies_parsed_at":"2024-09-09T20:35:19.799Z","dependency_job_id":"5d6ba83a-b8c3-498a-8f1f-fb30b8b7753e","html_url":"https://github.com/supabase-community/mock_supabase_http_client","commit_stats":{"total_commits":29,"total_committers":3,"mean_commits":9.666666666666666,"dds":0.1724137931034483,"last_synced_commit":"998e32ba2d4daaa37fa3c0e8284294ae69da6c17"},"previous_names":["supabase-community/mock_supabase_http_client"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/supabase-community/mock_supabase_http_client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase-community%2Fmock_supabase_http_client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase-community%2Fmock_supabase_http_client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase-community%2Fmock_supabase_http_client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase-community%2Fmock_supabase_http_client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/supabase-community","download_url":"https://codeload.github.com/supabase-community/mock_supabase_http_client/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase-community%2Fmock_supabase_http_client/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261375458,"owners_count":23149120,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flutter","supabase","supabase-client","supabase-flutter","testing"],"created_at":"2024-09-30T15:04:03.905Z","updated_at":"2025-06-26T19:35:07.197Z","avatar_url":"https://github.com/supabase-community.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MockSupabaseHttpClient\n\nAn mock http client for testing Supabase APIs.\nBy passing the `MockSupabaseHttpClient` to the Supabase client, you can create a mock Supabase client that you can use for unit testing your Supabase API calls without making actual network requests.\n\nIt works by intercepting the HTTP requests and returning the mock data you have inserted into the mock database. The data inserted into the mock database will be stored in memory.\n\n```dart\nimport 'package:mock_supabase_http_client/mock_supabase_http_client.dart';\nimport 'package:supabase/supabase.dart';\n\nfinal mockSupabase = SupabaseClient(\n  'https://mock.supabase.co', // Does not matter what URL you pass here as long as it's a valid URL\n  'fakeAnonKey', // Does not matter what string you pass here\n  httpClient: MockSupabaseHttpClient(),\n);\n```\n\n## Features\n\n- Add mock data to the mock Supabase client\n- Supports select, insert, update, upsert, and delete operations\n- Supports filtering, ordering, and limiting results\n- Supports referenced table operations\n- Can reset the mock data between tests\n\n## Installation\n\nAdd mock_supabase_http_client to your dev dependencies:\n```yaml\ndev_dependencies:\n  mock_supabase_http_client: ^0.0.1\n```\n\n## Usage\n\nYou can insert dummy data into the mock database and then test your Supabase API calls.\n\n```dart\nimport 'package:mock_supabase_http_client/mock_supabase_http_client.dart';\nimport 'package:supabase/supabase.dart';\nimport 'package:test/test.dart';\n\nvoid main() {\n  late final SupabaseClient mockSupabase;\n  late final MockSupabaseHttpClient mockHttpClient;\n\n  setUpAll(() {\n    mockHttpClient = MockSupabaseHttpClient();\n\n    // Pass the mock client to the Supabase client\n    mockSupabase = SupabaseClient(\n      'https://mock.supabase.co', // Does not matter what URL you pass here as long as it's a valid URL\n      'fakeAnonKey', // Does not matter what string you pass here\n      httpClient: MockSupabaseHttpClient(),\n    );\n  });\n\n  tearDown(() async {\n    // Reset the mock data after each test\n    mockHttpClient.reset();\n  });\n\n  tearDownAll(() {\n    // Close the mock client after all tests\n    mockHttpClient.close();\n  });\n\n  test('inserting data works', () async {\n    // Start by inserting some mock data into the mock database\n    await mockSupabase.from('posts').insert({'title': 'Hello, world!'});\n\n    // Then you can test your Supabase API calls\n    final posts = await mockSupabase.from('posts').select();\n    expect(posts.length, 1);\n    expect(posts.first, {'title': 'Hello, world!'});\n  });\n\n  // Because the mock Supabase client does not know the table schema, \n  // referenced table data has to be inserted in a way that you want to query it.\n  //\n  // The following example shows an example where posts table has a many-to-one \n  // relationship with authors table and a one-to-many relationship with comments table.\n  test('advanced querying with filtering and referenced tables', () async {\n    // posts table has a many-to-one relationship with authors table\n    // posts table has a one-to-many relationship with comments table\n    await mockSupabase.from('posts').insert([\n      {\n        'id': 1,\n        'title': 'First post',\n        'authors': {'id': 1, 'name': 'Author One'},\n        'comments': [\n          {'id': 1, 'content': 'First comment'},\n          {'id': 2, 'content': 'Second comment'}\n        ]\n      },\n      {\n        'id': 2,\n        'title': 'Second post',\n        'authors': {'id': 2, 'name': 'Author Two'},\n        'comments': [\n          {'id': 3, 'content': 'Third comment'},\n          {'id': 4, 'content': 'Fourth comment'},\n          {'id': 5, 'content': 'Fifth comment'}\n        ]\n      }\n    ]);\n\n    // Query posts with filtering and include referenced author data\n    final posts = await mockSupabase\n        .from('posts')\n        .select('*, authors(*), comments(*)')\n        .eq('authors.id', 1)\n        .order('id', ascending: false);\n\n    expect(posts.length, 2);\n    expect(posts, [\n      {\n        'id': 2,\n        'title': 'Second post',\n        'authors': {'id': 2, 'name': 'Author Two'},\n        'comments': [\n          {'id': 3, 'content': 'Third comment'},\n          {'id': 4, 'content': 'Fourth comment'},\n          {'id': 5, 'content': 'Fifth comment'},\n        ]\n      },\n      {\n        'id': 1,\n        'title': 'First post',\n        'authors': {'id': 1, 'name': 'Author One'},\n        'comments': [\n          {'id': 1, 'content': 'First comment'},\n          {'id': 2, 'content': 'Second comment'},\n        ]\n      },\n    ]);\n  });\n}\n```\n\n### Mocking Edge Functions\n\nYou can easily mock edge functions using the `registerEdgeFunction` method of `MockSupabaseHttpClient`. This method allows you to specify a handler function, giving you fine-grained control over the response based on the request body, HTTP method, and query parameters. You even have access to the mock database.\n\n```dart\n group('Edge Functions Client', () {\n    test('invoke registered edge function with POST', () async {\n      mockHttpClient.registerEdgeFunction('greet',\n          (body, queryParams, method, tables) {\n        return FunctionResponse(\n          data: {'message': 'Hello, ${body['name']}!'},\n          status: 200,\n        );\n      });\n\n      final response = await mockSupabase.functions.invoke(\n        'greet',\n        body: {'name': 'Alice'},\n      );\n\n      expect(response.status, 200);\n      expect(response.data, {'message': 'Hello, Alice!'});\n    });\n\n    test('invoke edge function with different HTTP methods', () async {\n      mockHttpClient.registerEdgeFunction('say-hello',\n          (body, queryParams, method, tables) {\n        final name = switch (method) {\n          HttpMethod.patch =\u003e 'Linda',\n          HttpMethod.post =\u003e 'Bob',\n          _ =\u003e 'Unknown'\n        };\n        return FunctionResponse(\n          data: {'hello': name},\n          status: 200,\n        );\n      });\n\n      var patchResponse = await mockSupabase.functions\n          .invoke('say-hello', method: HttpMethod.patch);\n      expect(patchResponse.data, {'hello': 'Linda'});\n\n      var postResponse = await mockSupabase.functions\n          .invoke('say-hello', method: HttpMethod.post);\n      expect(postResponse.data, {'hello': 'Bob'});\n    });\n\n    test('edge function receives query params and body', () async {\n      mockHttpClient.registerEdgeFunction('params-test',\n          (body, queryParams, method, tables) {\n        final city = queryParams['city'];\n        final street = body['street'] as String;\n        return FunctionResponse(\n          data: {'address': '$street, $city'},\n          status: 200,\n        );\n      });\n\n      final response = await mockSupabase.functions.invoke(\n        'params-test',\n        body: {'street': '123 Main St'},\n        queryParameters: {'city': 'Springfield'},\n      );\n\n      expect(response.data, {'address': '123 Main St, Springfield'});\n    });\n\n    test('edge function returns different content types', () async {\n      mockHttpClient.registerEdgeFunction('binary',\n          (body, queryParams, method, tables) {\n        return FunctionResponse(\n          data: Uint8List.fromList([1, 2, 3]),\n          status: 200,\n        );\n      });\n\n      var response = await mockSupabase.functions.invoke('binary');\n      expect(response.data is Uint8List, true);\n      expect((response.data as Uint8List).length, 3);\n\n      mockHttpClient.registerEdgeFunction('text',\n          (body, queryParams, method, tables) {\n        return FunctionResponse(\n          data: 'Hello, world!',\n          status: 200,\n        );\n      });\n\n      response = await mockSupabase.functions.invoke('text');\n      expect(response.data, 'Hello, world!');\n\n      mockHttpClient.registerEdgeFunction('json',\n          (body, queryParams, method, tables) {\n        return FunctionResponse(\n          data: {'key': 'value'},\n          status: 200,\n        );\n      });\n\n      response = await mockSupabase.functions.invoke('json');\n      expect(response.data, {'key': 'value'});\n    });\n\n    test('edge function modifies mock database', () async {\n      mockHttpClient.registerEdgeFunction('add-user',\n          (body, queryParams, method, tables) {\n        final users = tables['public.users'] ?? [];\n        final newUser = {\n          'id': users.length + 1,\n          'name': body['name'],\n        };\n        users.add(newUser);\n        tables['public.users'] = users;\n        return FunctionResponse(data: newUser, status: 201);\n      });\n\n      var users = await mockSupabase.from('users').select();\n      expect(users, isEmpty);\n\n      final response = await mockSupabase.functions.invoke(\n        'add-user',\n        body: {'name': 'Alice'},\n      );\n      expect(response.status, 201);\n      expect(response.data, {'id': 1, 'name': 'Alice'});\n\n      users = await mockSupabase.from('users').select();\n      expect(users, [\n        {'id': 1, 'name': 'Alice'}\n      ]);\n    });\n  });\n```\n\n### Mocking Errors\n\nYou can simulate error scenarios by configuring an error trigger callback. This is useful for testing how your application handles various error conditions:\n\n```dart\nvoid main() {\n  late final SupabaseClient mockSupabase;\n  late final MockSupabaseHttpClient mockHttpClient;\n\n  setUp(() {\n    // Configure error trigger\n    mockHttpClient = MockSupabaseHttpClient(\n      postgrestExceptionTrigger: (schema, table, data, type) {\n        // Simulate unique constraint violation on email\n        if (table == 'users' \u0026\u0026 type == RequestType.insert) {\n          throw PostgrestException(\n            message: 'duplicate key value violates unique constraint \"users_email_key\"',\n            code: '23505', // Postgres unique violation code\n          );\n        }\n        \n        // Simulate permission error for certain operations\n        if (table == 'private_data' \u0026\u0026 type == RequestType.select) {\n          throw PostgrestException(\n            message: 'permission denied for table private_data',\n            code: '42501', // Postgres permission denied code\n          );\n        }\n      },\n    );\n\n    mockSupabase = SupabaseClient(\n      'https://mock.supabase.co',\n      'fakeAnonKey',\n      httpClient: mockHttpClient,\n    );\n  });\n\n  test('handles duplicate email error', () async {\n    expect(\n      () =\u003e mockSupabase.from('users').insert({\n        'email': 'existing@example.com',\n        'name': 'Test User'\n      }),\n      throwsA(isA\u003cPostgrestException\u003e()),\n    );\n  });\n}\n```\n\n### RPC Functions\n\nYou can mock Remote Procedure Call (RPC) functions by registering them with the mock client:\n\n```dart\nvoid main() {\n  late final SupabaseClient mockSupabase;\n  late final MockSupabaseHttpClient mockHttpClient;\n\n  setUp(() {\n    mockHttpClient = MockSupabaseHttpClient();\n\n    // Register mock RPC functions\n    mockHttpClient.registerRpcFunction(\n      'get_user_status',\n      (params, tables) =\u003e {'status': 'active', 'last_seen': '2024-03-20'},\n    );\n\n    mockHttpClient.registerRpcFunction(\n      'calculate_total',\n      (params, tables) {\n        final amount = params['amount'] as num;\n        final tax = params['tax_rate'] as num;\n        return {\n          'total': amount + (amount * tax),\n          'tax_amount': amount * tax,\n        };\n      },\n    );\n\n    mockSupabase = SupabaseClient(\n      'https://mock.supabase.co',\n      'fakeAnonKey',\n      httpClient: mockHttpClient,\n    );\n  });\n\n  test('calls RPC function with parameters', () async {\n    final result = await mockSupabase.rpc(\n      'calculate_total',\n      params: {'amount': 100, 'tax_rate': 0.1},\n    );\n\n    expect(result, {\n      'total': 110.0,\n      'tax_amount': 10.0,\n    });\n  });\n\n  test('mocks complex RPC function using database state', () async {\n    // Insert some test data\n    await mockSupabase.from('orders').insert([\n      {'id': 1, 'user_id': 123, 'amount': 100},\n      {'id': 2, 'user_id': 123, 'amount': 200},\n    ]);\n\n    // Register RPC that uses the mock database state\n    mockHttpClient.registerRpcFunction(\n      'get_user_total_orders',\n      (params, tables) {\n        final userId = params['user_id'];\n        final orders = tables['public.orders'] as List\u003cMap\u003cString, dynamic\u003e\u003e;\n        \n        final userOrders = orders.where((order) =\u003e order['user_id'] == userId);\n        final total = userOrders.fold\u003cnum\u003e(\n          0,\n          (sum, order) =\u003e sum + (order['amount'] as num),\n        );\n\n        return {'total_orders': userOrders.length, 'total_amount': total};\n      },\n    );\n\n    final result = await mockSupabase.rpc(\n      'get_user_total_orders',\n      params: {'user_id': 123},\n    );\n\n    expect(result, {\n      'total_orders': 2,\n      'total_amount': 300,\n    });\n  });\n}\n```\n\n## Current Limitations\n\n- 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.\n- Nested referenced table data is not supported.\n    ```dart\n    // This is fine\n    final posts = await mockSupabase.from('posts').select('*, authors(*)');\n    // This will not return the correct data\n    final posts = await mockSupabase.from('posts').select('*, authors(*, comments(*))');\n    ```\n- `!inner` join is not supported.\n- Renaming column names is not supported.\n- count and head requests are not supported.\n- aggregate functions are not supported.\n- Respect nullsFirst on ordering is not supported.\n- The errors thrown by the mock Supabase client is not the same as the actual Supabase client.\n- The mock Supabase client does not support auth, realtime, storage, or calling edge functions.\n    - 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.\n\nWe will work on adding more features to the mock Supabase client to make it more feature complete.\n\n## Contributing\n\nContributions are welcome! Please open an issue or submit a pull request on GitHub.\n\n## License\n\nThis project is licensed under the MIT License.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupabase-community%2Fmock_supabase_http_client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsupabase-community%2Fmock_supabase_http_client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupabase-community%2Fmock_supabase_http_client/lists"}