Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flutter app fails to configure AWS Amplify (Null check operator used on a null value) #1255

Closed
pflugs30 opened this issue Jan 11, 2022 · 4 comments
Assignees
Labels
pending-close-response-required The issue will be closed if details necessary to reproduce the issue are not provided within 7 days.

Comments

@pflugs30
Copy link

Describe the bug
I ran into a problem while upgrading a production app from AWS Amplify Flutter 0.1.X to ^0.2.0. The Flutter app fails to configure the Amplify packages without error. I then created a brand new Flutter application, following the steps on the Getting Started documentation and the Authentication page. I experienced the exact same error, despite building a project from scratch, including the AWS resources.

To Reproduce
Steps to reproduce the behavior:

  1. Follow the steps on the Getting Started documentation.
  2. Add the auth plugin following these steps.
  3. Add a test file module, such as this one:
import 'package:flutter_test/flutter_test.dart';
    import 'package:amplify_flutter/amplify.dart';
    import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
    import 'package:aws_amplify_flutter_app/amplifyconfiguration.dart';
    
    void main() {
      test('can configure Amplify', () async {
        AmplifyAuthCognito authPlugin = AmplifyAuthCognito();
        await Amplify.addPlugin(authPlugin);
    
        try {
          await Amplify.configure(amplifyconfig);
        } on AmplifyAlreadyConfiguredException {
          print("Tried to reconfigure Amplify; this can occur when your app restarts on Android.");
        }
      });
    }
  1. Run the test using a command like: flutter test test\my_test.dart

Actual Behavior
When I run the test file above, I get the following output:

F:\dev\personal\aws_amplify_flutter_app>flutter test test\widget_test.dart
00:36 +0: can configure Amplify
Amplify plugin was not added
00:36 +0 -1: can configure Amplify [E]
  AmplifyException(message: Amplify plugin AmplifyAuthCognito was not added successfully., recoverySuggestion: We currently don't have a recovery suggestion for this exception., underlyingException: Null check operator used on a null value)
  package:amplify_flutter/amplify.dart 101:9  AmplifyClass.addPlugin

00:36 +0 -1: Some tests failed.

I had a suspicion that the Amplify packages don't play nicely with the test runner, so I ran the built the project and ran the tests on my Samsung Galaxy S21 5G running Android 11. When I ran flutter run test\my_test.dart, I observed this output:

F:\dev\personal\aws_amplify_flutter_app>flutter run test\widget_test.dart
Running "flutter pub get" in aws_amplify_flutter_app...          1,920ms
Launching test\widget_test.dart on SM G991U in debug mode...
Running Gradle task 'assembleDebug'...                            301.8s
√  Built build\app\outputs\flutter-apk\app-debug.apk.
Installing build\app\outputs\flutter-apk\app.apk...                14.1s
I/flutter (14091): 00:00 +0: can configure Amplify
I/flutter (14091): Amplify plugin was not added
I/flutter (14091): 00:00 +0: can configure Amplify [E]
I/flutter (14091):   AmplifyException(message: Amplify plugin AmplifyAuthCognito was not added successfully., recoverySuggestion: We currently don't have a recovery suggestion for this exception., underlyingException: Null check operator used on a null value)
I/flutter (14091):   package:amplify_flutter/amplify.dart 101:9                         AmplifyClass.addPlugin
I/flutter (14091):   ===== asynchronous gap ===========================
I/flutter (14091):   F:/dev/personal/aws_amplify_flutter_app/test/widget_test.dart 9:5  main.<fn>
I/flutter (14091):   ===== asynchronous gap ===========================
I/flutter (14091):   package:test_api/src/backend/declarer.dart 199:9                   Declarer.test.<fn>.<fn>
I/flutter (14091):   ===== asynchronous gap ===========================
I/flutter (14091):   package:test_api/src/backend/declarer.dart 197:7                   Declarer.test.<fn>
I/flutter (14091):   ===== asynchronous gap ===========================
I/flutter (14091):   package:test_api/src/backend/invoker.dart 257:7                    Invoker._waitForOutstandingCallbacks.<fn>
I/flutter (14091):
I/flutter (14091): Consider enabling the flag chain-stack-traces to receive more detailed exceptions.
I/flutter (14091): For example, 'dart test --chain-stack-traces'.
I/flutter (14091): 00:00 +0 -1: Some tests failed.

(Some UI debug messages elided...)

Syncing files to device SM G991U...                                989ms

Flutter run key commands.
r Hot reload.
R Hot restart.
h List all available interactive commands.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).

 Running with sound null safety 

An Observatory debugger and profiler on SM G991U is available at: http://127.0.0.1:62306/ZudipYxxYjM=/

Application finished.

In other words, I saw the same results running in the test runner as on a real device.

Expected behavior
I expect that the test will pass without issue as the Amplify CLI should have properly created an amplifyconfiguration.dart file and the packages load the configuration successfully.

Screenshots
Here's a screenshot of debugging the await Amplify.configure(amplifyconfig); line in Android Studio:
debugging

Note that in the screenshot I'm hovering over line 35 of method_channel_auth_cognito.dart where the watch window shows the same message ("Null check operator used on a null value") as can be seen from the test output.

Platform
Amplify Flutter current supports iOS and Android. This issue is reproducible in (check all that apply):
[X] Android
[X] iOS

Output of flutter doctor -v
F:\dev\personal\aws_amplify_flutter_app>flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 2.8.1, on Microsoft Windows [Version 10.0.19043.1415], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version 31.0.0-rc1)
[√] Chrome - develop for the web
[√] Android Studio (version 4.1)
[√] VS Code (version 1.63.2)
[√] Connected device (3 available)

• No issues found!
Dependencies (pubspec.lock)
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
amplify_analytics_plugin_interface:
  dependency: transitive
  description:
    name: amplify_analytics_plugin_interface
    url: "https://pub.dartlang.org"
  source: hosted
  version: "0.2.10"
amplify_api_plugin_interface:
  dependency: transitive
  description:
    name: amplify_api_plugin_interface
    url: "https://pub.dartlang.org"
  source: hosted
  version: "0.2.10"
amplify_auth_cognito:
  dependency: "direct main"
  description:
    name: amplify_auth_cognito
    url: "https://pub.dartlang.org"
  source: hosted
  version: "0.2.10"
amplify_auth_plugin_interface:
  dependency: transitive
  description:
    name: amplify_auth_plugin_interface
    url: "https://pub.dartlang.org"
  source: hosted
  version: "0.2.10"
amplify_core:
  dependency: transitive
  description:
    name: amplify_core
    url: "https://pub.dartlang.org"
  source: hosted
  version: "0.2.10"
amplify_datastore_plugin_interface:
  dependency: transitive
  description:
    name: amplify_datastore_plugin_interface
    url: "https://pub.dartlang.org"
  source: hosted
  version: "0.2.10"
amplify_flutter:
  dependency: "direct main"
  description:
    name: amplify_flutter
    url: "https://pub.dartlang.org"
  source: hosted
  version: "0.2.10"
amplify_storage_plugin_interface:
  dependency: transitive
  description:
    name: amplify_storage_plugin_interface
    url: "https://pub.dartlang.org"
  source: hosted
  version: "0.2.10"
async:
  dependency: transitive
  description:
    name: async
    url: "https://pub.dartlang.org"
  source: hosted
  version: "2.8.2"
boolean_selector:
  dependency: transitive
  description:
    name: boolean_selector
    url: "https://pub.dartlang.org"
  source: hosted
  version: "2.1.0"
characters:
  dependency: transitive
  description:
    name: characters
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.2.0"
charcode:
  dependency: transitive
  description:
    name: charcode
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.3.1"
clock:
  dependency: transitive
  description:
    name: clock
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.1.0"
collection:
  dependency: transitive
  description:
    name: collection
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.15.0"
crypto:
  dependency: transitive
  description:
    name: crypto
    url: "https://pub.dartlang.org"
  source: hosted
  version: "3.0.1"
cupertino_icons:
  dependency: "direct main"
  description:
    name: cupertino_icons
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.0.4"
date_time_format:
  dependency: transitive
  description:
    name: date_time_format
    url: "https://pub.dartlang.org"
  source: hosted
  version: "2.0.1"
fake_async:
  dependency: transitive
  description:
    name: fake_async
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.2.0"
flutter:
  dependency: "direct main"
  description: flutter
  source: sdk
  version: "0.0.0"
flutter_lints:
  dependency: "direct dev"
  description:
    name: flutter_lints
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.0.4"
flutter_test:
  dependency: "direct dev"
  description: flutter
  source: sdk
  version: "0.0.0"
lints:
  dependency: transitive
  description:
    name: lints
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.0.1"
matcher:
  dependency: transitive
  description:
    name: matcher
    url: "https://pub.dartlang.org"
  source: hosted
  version: "0.12.11"
meta:
  dependency: transitive
  description:
    name: meta
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.7.0"
path:
  dependency: transitive
  description:
    name: path
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.8.0"
plugin_platform_interface:
  dependency: transitive
  description:
    name: plugin_platform_interface
    url: "https://pub.dartlang.org"
  source: hosted
  version: "2.1.2"
sky_engine:
  dependency: transitive
  description: flutter
  source: sdk
  version: "0.0.99"
source_span:
  dependency: transitive
  description:
    name: source_span
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.8.1"
stack_trace:
  dependency: transitive
  description:
    name: stack_trace
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.10.0"
stream_channel:
  dependency: transitive
  description:
    name: stream_channel
    url: "https://pub.dartlang.org"
  source: hosted
  version: "2.1.0"
string_scanner:
  dependency: transitive
  description:
    name: string_scanner
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.1.0"
term_glyph:
  dependency: transitive
  description:
    name: term_glyph
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.2.0"
test_api:
  dependency: transitive
  description:
    name: test_api
    url: "https://pub.dartlang.org"
  source: hosted
  version: "0.4.3"
typed_data:
  dependency: transitive
  description:
    name: typed_data
    url: "https://pub.dartlang.org"
  source: hosted
  version: "1.3.0"
uuid:
  dependency: transitive
  description:
    name: uuid
    url: "https://pub.dartlang.org"
  source: hosted
  version: "3.0.5"
vector_math:
  dependency: transitive
  description:
    name: vector_math
    url: "https://pub.dartlang.org"
  source: hosted
  version: "2.1.1"
sdks:
dart: ">=2.15.1 <3.0.0"
flutter: ">=1.20.0"

Smartphone (please complete the following information):

  • Device: Tested on both Samsung Galaxy S21 and iPhone
  • OS: Android or iOS
  • Browser: Not tested
  • Version: Android 11

Additional context
pubspec.yaml

name: aws_amplify_flutter_app
description: A new Flutter application.
publish_to: 'none'
version: 1.0.0+1

environment:
  sdk: ">=2.15.1 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  # Version 0.2.10 of all AWS Amplify packages are installed
  amplify_flutter: ^0.2.0
  amplify_auth_cognito: ^0.2.0
  cupertino_icons: ^1.0.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^1.0.0

flutter:
  uses-material-design: true

amplifyconfiguration.dart (obfuscated)

const amplifyconfig = ''' {
    "UserAgent": "aws-amplify-cli/2.0",
    "Version": "1.0",
    "auth": {
        "plugins": {
            "awsCognitoAuthPlugin": {
                "UserAgent": "aws-amplify-cli/0.1.0",
                "Version": "0.1.0",
                "IdentityManager": {
                    "Default": {}
                },
                "CredentialsProvider": {
                    "CognitoIdentity": {
                        "Default": {
                            "PoolId": "us-east-1:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
                            "Region": "us-east-1"
                        }
                    }
                },
                "CognitoUserPool": {
                    "Default": {
                        "PoolId": "us-east-1_abcdefghi",
                        "AppClientId": "abcdefghijklmnopqrstuvwxy",
                        "Region": "us-east-1"
                    }
                },
                "Auth": {
                    "Default": {
                        "authenticationFlowType": "USER_SRP_AUTH",
                        "socialProviders": [],
                        "usernameAttributes": [],
                        "signupAttributes": [
                            "EMAIL"
                        ],
                        "passwordProtectionSettings": {
                            "passwordPolicyMinLength": 8,
                            "passwordPolicyCharacters": []
                        },
                        "mfaConfiguration": "OFF",
                        "mfaTypes": [
                            "SMS"
                        ],
                        "verificationMechanisms": [
                            "EMAIL"
                        ]
                    }
                }
            }
        }
    }
}''';
@Jordan-Nelson Jordan-Nelson added the to-be-reproduced Issues that have not been reproduced yet, but have reproduction steps provided label Jan 11, 2022
@Jordan-Nelson Jordan-Nelson self-assigned this Jan 11, 2022
@pflugs30
Copy link
Author

Update: I enabled all debugging on SDK within VS Code, and I stepped through my test code. I found the exact line of code which causes the issue:
More debugging

Here's a closeup of the Call Stack:
call stack

Looks like these channel classes and methods deal with some kind of Reflection (Dart is not my first language). I'd be surprised if this bug is within the Flutter core code itself, so perhaps there's either an issue with the instantiation of the channel class by the AWS Amplify library or with the way the Amplify tutorial/documentation have us configure the SDK? Happy to help debug further if that would help as our app is stalled until this gets resolved.

@Jordan-Nelson
Copy link
Member

Hello @pflugs30 - If you want to write a test that includes configuring amplify (or really interacting with Amplify at all), you should write an integration test. The /test directory in the flutter scaffold is intended for unit tests. You should stub/mock Amplify in you unit tests.

You can follow the flutter integration testing guide here, but there are really just two small changes you need to make to make this test work.

  1. install integration_test as a dev dependency. To do this, you can update the dev_depenency section of your pubspec file to the following:
dev_dependencies:
  flutter_test:
    sdk: flutter
  integration_test:
    sdk: flutter
  1. Create a new directory (or rename the existing directory) /integration_test/. You shouldn't need to change any of the code you wrote. Just move the existing file to the new dir.

Let me know if you have any questions.

@Jordan-Nelson
Copy link
Member

Documentation around testing is currently a gap. I created an issue to track this gap.

@Jordan-Nelson Jordan-Nelson added pending-close-response-required The issue will be closed if details necessary to reproduce the issue are not provided within 7 days. and removed to-be-reproduced Issues that have not been reproduced yet, but have reproduction steps provided labels Jan 11, 2022
@pflugs30
Copy link
Author

You are correct that using the integration test approach resolved the issue. Thank you further for making an issue to update the documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pending-close-response-required The issue will be closed if details necessary to reproduce the issue are not provided within 7 days.
Projects
None yet
Development

No branches or pull requests

2 participants