|
| 1 | +import 'dart:convert'; |
| 2 | + |
1 | 3 | import 'package:gotrue/gotrue.dart'; |
| 4 | +import 'package:http/http.dart'; |
2 | 5 | import 'package:test/test.dart'; |
3 | 6 |
|
4 | 7 | import 'mocks/otp_mock_client.dart'; |
@@ -100,6 +103,34 @@ void main() { |
100 | 103 | expect(client.currentUser?.email, testEmail); |
101 | 104 | }); |
102 | 105 |
|
| 106 | + test('verifyOTP() sends correct parameters in request body', () async { |
| 107 | + // Test with specific email and token values from the issue |
| 108 | + const testOtp = '329169'; |
| 109 | + const specificEmail = '[email protected]'; |
| 110 | + |
| 111 | + // Create a custom mock client that verifies the request body |
| 112 | + final verifyingMockClient = VerifyingOtpMockClient( |
| 113 | + expectedEmail: specificEmail, |
| 114 | + expectedToken: testOtp, |
| 115 | + ); |
| 116 | + |
| 117 | + final verifyingClient = GoTrueClient( |
| 118 | + url: 'https://example.com', |
| 119 | + httpClient: verifyingMockClient, |
| 120 | + asyncStorage: asyncStorage, |
| 121 | + ); |
| 122 | + |
| 123 | + // This should succeed if parameters are sent correctly |
| 124 | + await verifyingClient.verifyOTP( |
| 125 | + email: specificEmail, |
| 126 | + token: testOtp, |
| 127 | + type: OtpType.email, |
| 128 | + ); |
| 129 | + |
| 130 | + // Test passes if no exceptions were thrown |
| 131 | + expect(verifyingMockClient.requestWasValid, isTrue); |
| 132 | + }); |
| 133 | + |
103 | 134 | test('verifyOTP() with recovery type', () async { |
104 | 135 | final response = await client.verifyOTP( |
105 | 136 | email: testEmail, |
@@ -602,3 +633,85 @@ void main() { |
602 | 633 | }); |
603 | 634 | }); |
604 | 635 | } |
| 636 | + |
| 637 | +/// A mock client that verifies the request body contains expected email and token values |
| 638 | +class VerifyingOtpMockClient extends BaseClient { |
| 639 | + final String expectedEmail; |
| 640 | + final String expectedToken; |
| 641 | + bool requestWasValid = false; |
| 642 | + |
| 643 | + VerifyingOtpMockClient({ |
| 644 | + required this.expectedEmail, |
| 645 | + required this.expectedToken, |
| 646 | + }); |
| 647 | + |
| 648 | + @override |
| 649 | + Future<StreamedResponse> send(BaseRequest request) async { |
| 650 | + if (request.url.toString().contains('/verify') && request is Request) { |
| 651 | + final requestBody = json.decode(request.body) as Map<String, dynamic>; |
| 652 | + |
| 653 | + // Verify that email parameter maps to 'email' field |
| 654 | + if (requestBody['email'] != expectedEmail) { |
| 655 | + throw Exception( |
| 656 | + 'Expected email "$expectedEmail" in request body "email" field, ' |
| 657 | + 'but got "${requestBody['email']}"' |
| 658 | + ); |
| 659 | + } |
| 660 | + |
| 661 | + // Verify that token parameter maps to 'token' field |
| 662 | + if (requestBody['token'] != expectedToken) { |
| 663 | + throw Exception( |
| 664 | + 'Expected token "$expectedToken" in request body "token" field, ' |
| 665 | + 'but got "${requestBody['token']}"' |
| 666 | + ); |
| 667 | + } |
| 668 | + |
| 669 | + // Verify parameters are not swapped |
| 670 | + if (requestBody['email'] == expectedToken || requestBody['token'] == expectedEmail) { |
| 671 | + throw Exception( |
| 672 | + 'Parameters appear to be swapped! ' |
| 673 | + 'email field contains: "${requestBody['email']}", ' |
| 674 | + 'token field contains: "${requestBody['token']}"' |
| 675 | + ); |
| 676 | + } |
| 677 | + |
| 678 | + requestWasValid = true; |
| 679 | + |
| 680 | + // Return a valid response |
| 681 | + final now = DateTime.now().toIso8601String(); |
| 682 | + return StreamedResponse( |
| 683 | + Stream.value(utf8.encode(jsonEncode({ |
| 684 | + 'access_token': 'mock-access-token', |
| 685 | + 'token_type': 'bearer', |
| 686 | + 'expires_in': 3600, |
| 687 | + 'refresh_token': 'mock-refresh-token', |
| 688 | + 'user': { |
| 689 | + 'id': 'mock-user-id', |
| 690 | + 'aud': 'authenticated', |
| 691 | + 'role': 'authenticated', |
| 692 | + 'email': expectedEmail, |
| 693 | + 'email_confirmed_at': now, |
| 694 | + 'confirmed_at': now, |
| 695 | + 'last_sign_in_at': now, |
| 696 | + 'created_at': now, |
| 697 | + 'updated_at': now, |
| 698 | + 'app_metadata': { |
| 699 | + 'provider': 'email', |
| 700 | + 'providers': ['email'], |
| 701 | + }, |
| 702 | + 'user_metadata': {}, |
| 703 | + 'identities': [], |
| 704 | + }, |
| 705 | + }))), |
| 706 | + 200, |
| 707 | + request: request, |
| 708 | + ); |
| 709 | + } |
| 710 | + |
| 711 | + return StreamedResponse( |
| 712 | + Stream.value(utf8.encode(jsonEncode({'error': 'Unhandled request'}))), |
| 713 | + 404, |
| 714 | + request: request, |
| 715 | + ); |
| 716 | + } |
| 717 | +} |
0 commit comments