Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass an environment variable to a flutter driver test

Tags:

flutter

dart

I want to pass an environment variable to a flutter drive test.

Being able to read the value in the launched application or the test code would both be fine, because I need it in the application and if I could only get it in the test code, I could pass it to the application using driver.requestData()

For example Travis allows me to specify environment variables that are not exposed in any way (like script content and log output).

I want to specify username and password this way so to be used inside the application.

Setting environment variables in Flutter is a similar question, but that seems overly complicated for my use case.

like image 722
Günter Zöchbauer Avatar asked Sep 28 '17 17:09

Günter Zöchbauer


People also ask

How do you set environment in Flutter?

In order to load proper environment configuration in our Flutter app, we will create a class called Environment which can set configuration dynamically. Since the Environment class has a singleton implementation, this ensures that the environment configuration doesn't change through out the application lifecycle.

What is .ENV file in Flutter?

env file which can be used throughout the application. The twelve-factor app stores config in environment variables (often shortened to env vars or env). Env vars are easy to change between deploys without changing any code... they are a language- and OS-agnostic standard.


3 Answers

I tried using Dart's Platform.environment to read in env variables before running driver tests and it seems to work fine. Below is a simple example that sets the output directory for the test summaries using the FLUTTER_DRIVER_RESULTS env variable.

import 'dart:async';
import 'dart:io' show Platform;

import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';

void main() {
  // Load environmental variables
  String resultsDirectory =
    Platform.environment['FLUTTER_DRIVER_RESULTS'] ?? '/tmp';
  print('Results directory is $resultsDirectory');

  group('increment button test', () {
    FlutterDriver driver;

    setUpAll(() async {
      // Connect to the app
      driver = await FlutterDriver.connect();
    });

    tearDownAll(() async {
      if (driver != null) {
        // Disconnect from the app
        driver.close();
      }
    });

    test('measure', () async {
      // Record the performance timeline of things that happen
      Timeline timeline = await driver.traceAction(() async {
        // Find the scrollable user list
        SerializableFinder incrementButton = find.byValueKey(
            'increment_button');

        // Click the button 10 times
        for (int i = 0; i < 10; i++) {
          await driver.tap(incrementButton);

          // Emulate time for a user's finger between taps
          await new Future<Null>.delayed(new Duration(milliseconds: 250));
        }

      });
        TimelineSummary summary = new TimelineSummary.summarize(timeline);
        summary.writeSummaryToFile('increment_perf',
            destinationDirectory: resultsDirectory, pretty: true);
        summary.writeTimelineToFile('increment_perf',
            destinationDirectory: resultsDirectory, pretty: true);
    });
  });
}
like image 157
Matt S. Avatar answered Oct 06 '22 16:10

Matt S.


The .env package serves me well:

include:

import 'package:dotenv/dotenv.dart' show load, env;

load:

load();

use:

test('can log in', () async {
      await driver.tap(emailFieldFinder);
      await driver.enterText(env['USERNAME']);
      await driver.tap(passwordFieldFinder);
      await driver.enterText(env['PASSWORD']);
      await driver.tap(loginButtonFinder);

      await Future<Null>.delayed(Duration(seconds: 2));

      expect(await driver.getText(mainMessageFinder), "Welcome");
});
like image 39
Jannie Theunissen Avatar answered Oct 06 '22 14:10

Jannie Theunissen


I encountered the same need to pass an environment variable for test application on a device in a Flutter driver test. The challenge was that test applications cannot read environment variables directly from flutter drive command.

Here is how I solved the problem. The test name for is "field_value_behaviors.dart". Environment variable name is FIRESTORE_IMPLEMENTATION.

Flutter Drive Command

Specify environment variable when running flutter drive command:

$ FIRESTORE_IMPLEMENTATION=cloud_firestore flutter drive --target=test_driver/field_value_behaviors.dart

Driver Program

Driver program ("field_value_behaviors_test.dart") runs as part of flutter drive program. It can read environment variables:

  String firestoreImplementation =
      Platform.environment['FIRESTORE_IMPLEMENTATION'];

Further, the driver program sends the value to test application running on a device through driver.requestData.

  final FlutterDriver driver = await FlutterDriver.connect();
  // Sends the choice to test application running on a device
  await driver.requestData(firestoreImplementation);
  await driver.requestData('waiting_test_completion',
      timeout: const Duration(minutes: 1));
  ...

Test Application

Test application ("field_value_behaviors.dart") has group() and test() function calls and runs on a device (simulator). Therefore it cannot read the environment variable directly from flutter drive command. Luckily, the test application can receive String messages from the driver program through enableFlutterDriverExtension():

void main() async {
  final Completer<String> firestoreImplementationQuery = Completer<String>();
  final Completer<String> completer = Completer<String>();

  enableFlutterDriverExtension(handler: (message) {
    if (validImplementationNames.contains(message)) {
      // When value is 'cloud_firestore' or 'cloud_firestore_mocks'
      firestoreImplementationQuery.complete(message);
      return Future.value(null);
    } else if (message == 'waiting_test_completion') {
      // Have Driver program wait for this future completion at tearDownAll.
      return completer.future;
    } else {
      fail('Unexpected message from Driver: $message');
    }
  });
  tearDownAll(() {
    completer.complete(null);
  });

The test application changes the behavior based on the resolved value of firestoreImplementationQuery.future:

  firestoreFutures = {
    // cloud_firestore_mocks
    'cloud_firestore_mocks': firestoreImplementationQuery.future.then((value) =>
        value == cloudFirestoreMocksImplementationName
            ? MockFirestoreInstance()
            : null),

Conclusion: read environment variable by Platform.environment in your driver program. Pass it to your test application by driver.requestData argument.

The implementation is in this PR: https://github.com/atn832/cloud_firestore_mocks/pull/54

like image 4
suztomo Avatar answered Oct 06 '22 14:10

suztomo