java-james / flutter_dotenv

Loads environment variables from `.env`.
https://pub.dartlang.org/packages/flutter_dotenv
MIT License
213 stars 48 forks source link

Loading an env inside a test fails #14

Closed brenoasm closed 2 years ago

brenoasm commented 4 years ago

Hi, I'm trying to load a .env.test inside a test, despite not throwing an error, no data is loaded.

group(
    'Testing',
    () {
      test('test env', () async {
        await DotEnv().load('environments/.env.test');

        var test = DotEnv().env;

        print(test);
      });
    },
  );

Inside the application's main method everything works fine. Is there something I'm doing wrong?

Thanks in advance.

0p3r4t0r commented 4 years ago

I'm stuck on something similar. Add the following to your test.

setUpAll(() async {
    /// Initialize test widgets to allow access to dot env.
    TestWidgetsFlutterBinding.ensureInitialized();
    await DotEnv().load();
});

You can now get env variables in your test. However, string interpolation doesn't work properly for me.

Example: In my .env

TEST_ONE="test"
TEST_TWO="test-${TEST_ONE}"

In my test

void main () {
    setUpAll(() async {
        /// Initialize test widgets to allow access to dot env.
        TestWidgetsFlutterBinding.ensureInitialized();
        await DotEnv().load();
    });

    test('env loads?', () {
        print(DotEnv().env['TEST_ONE']); // --> test
        print(DotEnv().env['TEST_ONE']); // --> test-${TEST_ONE}
    });
}
brenoasm commented 4 years ago

I'm stuck on something similar. Add the following to your test.

setUpAll(() async {
    /// Initialize test widgets to allow access to dot env.
    TestWidgetsFlutterBinding.ensureInitialized();
    await DotEnv().load();
});

You can now get env variables in your test. However, string interpolation doesn't work properly for me.

Example: In my .env

TEST_ONE="test"
TEST_TWO="test-${TEST_ONE}"

In my test

void main () {
    setUpAll(() async {
        /// Initialize test widgets to allow access to dot env.
        TestWidgetsFlutterBinding.ensureInitialized();
        await DotEnv().load();
    });

    test('env loads?', () {
        print(DotEnv().env['TEST_ONE']); // --> test
        print(DotEnv().env['TEST_ONE']); // --> test-${TEST_ONE}
    });
}

I know the interpolation works normally because my app depends on it. How can I get it to work in tests?

I'll test, thanks a lot!

0p3r4t0r commented 4 years ago

Okay I've got my .env working in tests.

Note: flutter_dot env doesn't handle string interpolation at all and you have to do it yourself.

  1. Because DotEnv doesn't interpolate variables I ended up doing in manually and created a helper class.
    
    import 'package:flutter_dotenv/flutter_dotenv.dart';
    import 'package:flutter_test/flutter_test.dart'

class DotEnvHelper { static Future load() async { /// Load the DotEnv, then interpolate variables and add them to /// DotEnv again. Call this at the beginning of your tests /// after calling [TestWidgetsFlutterBinding.ensureInitialized]. await DotEnv().load(); DotEnv().env = DotEnvMock._interpolate(DotEnv().env); return null; }

static Map<String, String> _interpolate(Map<String, String> env) { /// Unfortunately [DotEnv] doesn't handle variable interpolation, so /// we have to do it manually.

Map<String, String> interpolated = {};

/// group(0) -> ${example}  group(1) -> example
final RegExp variablesWithBrackets = RegExp(r'\${([^}]+)}'); // ${example}
/// group(0) -> $example    group(1) -> example
final RegExp variablesWithoutBrackets = RegExp(r'\$(\w+)\b'); // $example

final List<RegExp> regexes = [
  variablesWithBrackets,
  variablesWithoutBrackets,
];

for (var e in env.entries) {
  for (RegExp regex in regexes) {
    for (Match match in regex.allMatches(e.value)) {
      String substitute = match.group(0);
      String key = match.group(1);
      interpolated[e.key] = interpolated.containsKey(e.key)
          ? interpolated[e.key].replaceAll(substitute, env[key])
          : env[e.key].replaceAll(substitute, env[key]);
    }
  }
}

for (var e in interpolated.entries) {
  env[e.key] = e.value;
}

return env;

} }



2. Instead of calling `await DotEnv().load()` you would now call `await DotEnvHelper.load()`, then you can access env variables the normal way using `DotEnv().env['variable name']`. Also all of your other code should work because `DotEnvHelper` wraps the origincal `DotEnv()` singleton.

If anyone else gets a chance to try this solution out let me know. If it works for people then maybe I'll open a PR.
java-james commented 2 years ago

Thank you for working to provide the workarounds above.

The latest version provides a test load function for tests. See README.md & discussion: https://github.com/java-james/flutter_dotenv/discussions/58 for usage info.

Please let me know if this doesn't resolve the issue & we can reopen this issue.