A Flutter tool that makes golden testing easy.

Related tags

Templates alchemist
Overview

🧙🏼 Alchemist

Very Good Ventures

Betterment

Developed with 💙 by Very Good Ventures 🦄 and Betterment ☀️ .

ci codecov pub package License: MIT


A Flutter tool that makes golden testing easy.

Alchemist is a Flutter package that provides functions, extensions and documentation to support golden tests.

Heavily inspired by Ebay Motor's golden_toolkit package, Alchemist attempts to make writing and running golden tests in Flutter easier.

Feature Overview

Table of Contents

About platform tests vs. CI tests

Alchemist can perform two kinds of golden tests.

One is platform tests, which generate golden files with human readable text. These can be considered regular golden tests and are usually only run on a local machine.

Example platform golden test

The other is CI tests, which look and function the same as platform tests, except that the text blocks are replaced with colored squares.

Example CI golden test

The reason for this distinction is that the output of platform tests is dependent on the platform the test is running on. In particular, individual platforms are known to render text differently than others. This causes readable golden files generated on macOS, for example, to be ever so slightly off from the golden files generated on other platforms, such as Windows or Linux, causing CI systems to fail the test. CI tests, on the other hand, were made to circumvent this, and will always have the same output regardless of the platform.

Additionally, CI tests are always run using the Ahem font family, which is a font that solely renders square characters. This is done to ensure that CI tests are platform agnostic -- their output is always consistent regardless of the host platform.

Basic usage

Writing the test

In your project's test/ directory, add a file for your widget's tests. Then, write and run golden tests by using the goldenTest function.

We recommend putting all golden tests related to the same component into a test group.

Every goldenTest commonly contains a group of scenarios related to each other (for example, all scenarios that test the same constructor or widget in a particular context).

This example shows a basic golden test for ListTiles that makes use of some of the more advanced features of the goldenTest API to control the output of the test.

import 'package:alchemist/alchemist.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  group('ListTile Golden Tests', () {
    goldenTest(
      'renders correctly',
      fileName: 'list_tile',
      constraints: const BoxConstraints(maxWidth: 600),
      builder: () => GoldenTestGroup(
        columnWidthBuilder: (_) => const FlexColumnWidth(),
        children: [
          GoldenTestScenario(
            name: 'with title',
            child: ListTile(
              title: Text('ListTile.title'),
            ),
          ),
          GoldenTestScenario(
            name: 'with title and subtitle',
            child: ListTile(
              title: Text('ListTile.title'),
              subtitle: Text('ListTile.subtitle'),
            ),
          ),
          GoldenTestScenario(
            name: 'with trailing icon',
            child: ListTile(
              title: Text('ListTile.title'),
              trailing: Icon(Icons.chevron_right_rounded),
            ),
          ),
        ],
      ),
    );
  });
}

Then, simply run Flutter test and pass the --update-goldens flag to generate the golden files.

flutter test --update-goldens

Recommended Setup Guide

For a more detailed explanation on how Betterment uses Alchemist, read the included Recommended Setup Guide.

Test groups

While the goldenTest function can take in and performs tests on any arbitrary widget, it is most commonly given a GoldenTestGroup. This is a widget used for organizing a set of widgets that groups multiple testing scenarios together and arranges them in a table format.

Alongside the children parameter, GoldenTestGroup contains two additional properties that can be used to customize the resulting table view:

Field Default Description
int? columns null The amount of columns in the grid. If left unset, this will be determined based on the amount of children.
ColumnWidthBuilder? columnWidthBuilder null A function that returns the width for each column. If left unset, the width of each column is determined by the width of the widest widget in that column.

Test scenarios

Golden test scenarios are typically encapsulated in a GoldenTestScenario widget. This widget contains a name property that is used to identify the scenario, along with the widget it should display. The regular constructor allows a name and child to be passed in, but the .builder and .withTextScaleFactor constructors allow the use of a widget builder and text scale factor to be passed in respectively.

Generating the golden file

To run the test and generate the golden file, run flutter test with the --update-goldens flag.

# Should always succeed
flutter test --update-goldens

After all golden tests have run, the generated golden files will be in the goldens/ci/ directory relative to the test file. Depending on the platform the test was run on (and the current AlchemistConfig), platform goldens will be in the goldens/<platform_name> directory.

lib/
test/
├─ goldens/
│  ├─ ci/
│  │  ├─ my_widget.png
│  ├─ macos/
│  │  ├─ my_widget.png
│  ├─ linux/
│  │  ├─ my_widget.png
│  ├─ windows/
│  │  ├─ my_widget.png
├─ my_widget_golden_test.dart
pubspec.yaml

Testing and comparing

When you want to run golden tests regularly and compare them to the generated golden files (in a CI process for example), simply run flutter test.

By default, all golden tests will have a "golden" tag, meaning you can select when to run golden tests.

# Run all tests.
flutter test

# Only run golden tests.
flutter test --tags golden

# Run all tests except golden tests.
flutter test --exclude-tags golden

Advanced usage

Alchemist has several extensions and mechanics to accommodate for more advanced golden testing scenarios.

About AlchemistConfig

All tests make use of the AlchemistConfig class. This configuration object contains various settings that can be used to customize the behavior of the tests.

A default AlchemistConfig is provided for you, and contains the following settings:

Field Default Description
bool forceUpdateGoldenFiles false If true, the golden files will always be regenerated, regardless of the --update-goldens flag.
ThemeData? theme null The theme to use for all tests. If null, the default ThemeData.light() will be used.
PlatformGoldensConfig platformGoldensConfig const PlatformGoldensConfig() The configuration to use when running readable golden tests on a non-CI host.
CiGoldensConfig ciGoldensConfig const CiGoldensConfig() The configuration to use when running obscured golden tests in a CI environment.

Both the PlatformGoldensConfig and CiGoldensConfig classes contain a number of settings that can be used to customize the behavior of the tests. These are the settings both of these objects allow you to customize:

Field Default Description
bool enabled true Indicates if this type of test should run. If set to false, this type of test is never allowed to run. Defaults to true.
bool obscureText true for CI, false for platform Indicates if the text in the rendered widget should be obscured by colored rectangles. This is useful for circumventing issues with Flutter's font rendering between host platforms.
bool renderShadows false for CI, true for platform Indicates if shadows should actually be rendered, or if they should be replaced by opaque colors. This is useful because shadow rendering can be inconsistent between test runs.
FilePathResolver filePathResolver <_defaultFilePathResolver> A function that resolves the path to the golden file, relative to the test that generates it. By default, CI golden test files are placed in goldens/ci/, and readable golden test files are placed in goldens/.
ThemeData? theme null The theme to use for this type of test. If null, the enclosing AlchemistConfig's theme will be used, or ThemeData.light() if that is also null. Note that CI tests are always run using the Ahem font family, which is a font that solely renders square characters. This is done to ensure that CI tests are always consistent across platforms.

Alongside these arguments, the PlatformGoldensConfig contains an additional setting:

Field Default Description
Set<HostPlatform> platforms All platforms The platforms that platform golden tests should run on. By default, this is set to all platforms, meaning that a golden file will be generated if the current platform matches any platforms in the provided set.

Using a custom config

The current AlchemistConfig can be retrieved at any time using AlchemistConfig.current().

A custom can be set by using AlchemistConfig.runWithConfig. Any code executed within this function will cause AlchemistConfig.current() to return the provided config. This is achieved using Dart's zoning system.

void main() {
  print(AlchemistConfig.current().forceUpdateGoldenFiles);
  // > false

  AlchemistConfig.runWithConfig(
    config: AlchemistConfig(
      forceUpdateGoldenFiles: true,
    ),
    run: () {
      print(AlchemistConfig.current().forceUpdateGoldenFiles);
      // > true
    },
  );
}
For all tests

A common way to use this mechanic to configure tests for all your tests in a particular package is by using a flutter_test_config.dart file.

Create a flutter_test_config.dart file in the root of your project's test/ directory. This file should have the following contents by default:

import 'dart:async';

Future<void> testExecutable(FutureOr<void> Function() testMain) async {
  await testMain();
}

This file is executed every time a test file is about to be run. To set a global config, simply wrap the testMain function in a AlchemistConfig.runWithConfig call, like so:

import 'dart:async';

import 'package:alchemist/alchemist.dart';

Future<void> testExecutable(FutureOr<void> Function() testMain) async {
  return AlchemistConfig.runWithConfig(
    config: AlchemistConfig(
      // Configure the config here.
    ),
    run: testMain,
  );
}

Any test executed in the package will now use the provided config.

For single tests or groups

A config can also be set for a single test or test group, which will override the default for those tests. This can be achieved by wrapping that group or test in a AlchemistConfig.runWithConfig call, like so:

void main() {
  group('with default config', () {
    test('test', () {
      expect(
        AlchemistConfig.current().forceUpdateGoldenFiles,
        isFalse,
      );
    });
  });

  AlchemistConfig.runWithConfig(
    config: AlchemistConfig(
      forceUpdateGoldenFiles: true,
    ),
    run: () {
      group('with overridden config', () {
        test('test', () {
          expect(
            AlchemistConfig.current().forceUpdateGoldenFiles,
            isTrue,
          );
        });
      });
    },
  );
}
Merging and copying configs

Additionally, settings for a given code block can be partially overridden by using AlchemistConfig.copyWith or, more commonly, AlchemistConfig.merge. The copyWith method will create a copy of the config it is called on, and then override the settings passed in. The merge is slightly more flexible, allowing a second AlchemistConfig (or null) to be passed in, after which a copy will be created of the instance, and all settings defined on the provided config will replace ones on the instance.

Fortunately, the replacement mechanic of merge makes it possible to replace deep/nested values easily, like this:

Click to open AlchemistConfig.merge example
void main() {
  // The top level config is defined here.
  AlchemistConfig.runWithConfig(
    config: AlchemistConfig(
      forceUpdateGoldenFiles: true,
      platformGoldensConfig: PlatformGoldensConfig(
        renderShadows: false,
        fileNameResolver: (String name) => 'top_level_config/goldens/$name.png',
      ),
    ),
    run: () {
      final currentConfig = AlchemistConfig.current();

      print(currentConfig.forceUpdateGoldenFiles);
      // > true
      print(currentConfig.platformGoldensConfig.renderShadows);
      // > false
      print(currentConfig.platformGoldensConfig.fileNameResolver('my_widget'));
      // > top_level_config/goldens/my_widget.png

      AlchemistConfig.runWithConfig(
        // Here, the current config (defined above) is merged
        // with a new config, where only the defined options are
        // replaced, preserving the rest.
        config: AlchemistConfig.current().merge(
            AlchemistConfig(
              platformGoldensConfig: PlatformGoldensConfig(
                renderShadows: true,
              ),
            ),
          ),
        ),
        run: () {
          // AlchemistConfig.current() will now return the merged config.
          final currentConfig = AlchemistConfig.current();

          print(currentConfig.forceUpdateGoldenFiles);
          // > true (preserved from the top level config)
          print(currentConfig.platformGoldensConfig.renderShadows);
          // > true (changed by the newly merged config)
          print(currentConfig.platformGoldensConfig.fileNameResolver('my_widget'));
          // > top_level_config/goldens/my_widget.png (preserved from the top level config)
        },
      );
    },
  );
}

Simulating gestures

Some golden tests may require some form of user input to be performed. For example, to make sure a button shows the right color when being pressed, a test may require a tap gesture to be performed while the golden test image is being generated.

These kinds of gestures can be performed by providing the goldenTest function with a whilePerforming argument. This parameter takes a function that will be used to find the widget that should be pressed. There are some default interactions already provided, such as press and longPress.

void main() {
  goldenTest(
    'ElevatedButton renders tap indicator when pressed',
    fileName: 'elevated_button_pressed',
    whilePerforming: press(find.byType(ElevatedButton)),
    widget: GoldenTestGroup(
      children: [
        GoldenTestScenario(
          name: 'pressed',
          child: ElevatedButton(
            onPressed: () {},
            child: Text('Pressed'),
          ),
        ),
      ],
    ),
  );
}

Automatic/custom image sizing

By default, Alchemist will automatically find the smallest possible size for the generated golden image and the widgets it contains, and will resize the image accordingly.

The default size and this scaling behavior are configurable, and fully encapsulated in the constraints argument to the goldenTest function.

The constraints are set to const BoxConstraints() by default, meaning no minimum or maximum size will be enforced.

If a minimum width or height is set, the image will be resized to that size as long as it would not clip the widgets it contains. The same is true for a maximum width or height.

If the passed in constraints are tight, meaning the minimum width and height are equal to the maximum width and height, no resizing will be performed and the image will be generated at the exact size specified.

Custom pumping behavior

Before running every golden test, the goldenTest function will call its pumpBeforeTest function. This function is used to prime the widget tree prior to generating the golden test image. By default, the tree is pumped and settled (using tester.pumpAndSettle()), but in some scenarios, custom pumping behavior may be required.

In these cases, a different pumpBeforeTest function can be provided to the goldenTest function. A set of predefined functions are included in this package, including pumpOnce, pumpNTimes(n), and onlyPumpAndSettle, but custom functions can be created as well.

Additionally, there is a precacheImages function, which can be passed to pumpBeforeTest in order to preload all images in the tree, so that they will appear in the generated golden files.

Custom text scale factor

The GoldenTestScenario.withTextScaleFactor constructor allows a custom text scale factor value to be provided for a single scenario. This can be used to test text rendering at different sizes.

To set a default scale factor for all scenarios within a test, the goldenTest function allows a default textScaleFactor to be provided, which defaults to 1.0.

Resources

Comments
  • chore: Bump version, remove explicit test version

    chore: Bump version, remove explicit test version

    Description

    Bump version, fix dependency resolution

    /domain @btrautmann @samandmoore /platform @btrautmann @samandmoore

    Type of Change

    • [ ] ✨ New feature (non-breaking change which adds functionality)
    • [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
    • [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change)
    • [ ] 🧹 Code refactor
    • [ ] ✅ Build configuration change
    • [ ] 📝 Documentation
    • [x] 🗑️ Chore
    opened by definitelyokay 32
  • chore: Fix link

    chore: Fix link

    Description

    Should fix #11

    /domain @btrautmann /platform @btrautmann

    Type of Change

    • [ ] ✨ New feature (non-breaking change which adds functionality)
    • [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
    • [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change)
    • [ ] 🧹 Code refactor
    • [ ] ✅ Build configuration change
    • [ ] 📝 Documentation
    • [x] 🗑️ Chore
    opened by definitelyokay 14
  • fix(readme): Update README.md to fix pub link

    fix(readme): Update README.md to fix pub link

    Description

    Fixes pub_link in README

    Resolves the issue seen on main for broken pub_link

    Screen Shot 2022-02-22 at 15 14 39

    Type of Change

    • [ ] ✨ New feature (non-breaking change which adds functionality)
    • [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
    • [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change)
    • [ ] 🧹 Code refactor
    • [ ] ✅ Build configuration change
    • [x] 📝 Documentation
    • [ ] 🗑️ Chore

    /domain @Betterment/alchemist-maintainers /no-platform

    opened by btrautmann 10
  • feat: Add generic interactions

    feat: Add generic interactions

    Description

    Introduces a new minor version and refactors interactions to be generic. Thanks to @Kirpal for pairing with me. @jeroen-meijer please review 😉

    Essentially, this introduces a new built-in interaction for longPress so that you don't have to hijack the pumpAction to do your custom interactions, and lets you easily add your own interactions.

    Note that pumpAction now runs after the widget is loaded but before any provided interaction is run, since pumpAction seems intended to allow you to have custom pump behavior immediately after loading the widget. Any additional pumping needed for the interaction can be done in the provided interaction callback.

    Type of Change

    • [x] ✨ New feature (non-breaking change which adds functionality)
    • [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
    • [x] ❌ Breaking change (fix or feature that would cause existing functionality to change)
    • [x] 🧹 Code refactor
    • [ ] ✅ Build configuration change
    • [ ] 📝 Documentation
    • [ ] 🗑️ Chore
    opened by definitelyokay 10
  • feat: add improved example project

    feat: add improved example project

    Description

    This PR adds an example project that showcases how to test a pair of example widgets.

    The example.md file is preserved (with some minor change). This way, users on pub.dev will still see a single example file, but may also consult the full example project if they wish.

    image

    Type of Change

    • [x] ✨ New feature (non-breaking change which adds functionality)
    • [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
    • [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change)
    • [ ] 🧹 Code refactor
    • [ ] ✅ Build configuration change
    • [x] 📝 Documentation
    • [ ] 🗑️ Chore
    opened by jeroen-meijer 9
  • chore(deps): bump subosito/flutter-action from 1.5.3 to 2.3.0

    chore(deps): bump subosito/flutter-action from 1.5.3 to 2.3.0

    Bumps subosito/flutter-action from 1.5.3 to 2.3.0.

    Release notes

    Sourced from subosito/flutter-action's releases.

    v2.3.0

    No release notes provided.

    v2.2.1

    quiet unzip

    v2.2.0

    add cache-path option

    v2.1.0

    add cache option

    v2.0.4

    add actions/cache support

    v2.0.3

    fix PUB_CACHE env

    v2.0.2

    update v2 readme

    v2.0.1

    written as shell script

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 9
  • docs: Update changelog

    docs: Update changelog

    Description

    Oops 🤷‍♀️

    /domain @btrautmann @samandmoore /platform @btrautmann @samandmoore

    Type of Change

    • [ ] ✨ New feature (non-breaking change which adds functionality)
    • [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
    • [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change)
    • [ ] 🧹 Code refactor
    • [ ] ✅ Build configuration change
    • [x] 📝 Documentation
    • [ ] 🗑️ Chore
    opened by definitelyokay 8
  • Localization support

    Localization support

    Is there an existing feature request for this?

    • [X] I have searched the existing issues.

    Command

    It would be awesome to add a support for the localisation in the library

    Description

    First of all, thanks for an awesome library and your work!

    The problem is, I haven't found a proper way to add localisations delegate to the golden test, and this feature is extremely important to have in order to test any widget with localisation.

    I've added localizationsDelegates param in my fork to enable localisation, and it actually worked. But the problem is, after adding an AppLocalizationDelegate to the MaterialApp, alchemist has stopped rendering any kind of images. Any asset or file image would become transparent. However, after removing the delegate, images appear again. I've tested adding the same AppLocalizationDelegate to the MaterialApp with a golden_toolkit library, and there was no such problem (images were rendered and localisation worked as well).

    Maybe you have any ideas on how to add a localizationsDelegates to the test in a way that prevents this issue with rendering images?

    Reasoning

    I think that supporting localisation in the library would greatly increase the usability

    Additional context and comments

    You can refer to my closed PR, where I've added the coreWrapper: https://github.com/Betterment/alchemist/pull/43

    opened by t-girniak 6
  • request: different screen size

    request: different screen size

    Is there an existing feature request for this?

    • [X] I have searched the existing issues.

    Command

    I would love if I could run my tests with a lot of screen sizes (iPhone / iPad / desktop)

    Description

    I would love if I could generate file the same way golden toolkit is doing

    Screenshot 2022-03-22 at 16 17 53

    Reasoning

    Since variant is used for the platform, I cannot find a way to keep the device type properly organized with Alchemist. Variants are useful to get also a nice overview in IDEs.

    Screenshot 2022-03-22 at 16 25 39

    Additional context and comments

    No response

    enhancement 
    opened by Lyokone 6
  • Golden Testing on iOS and Android

    Golden Testing on iOS and Android

    Is there an existing feature request for this?

    • [X] I have searched the existing issues.

    Command

    Golden Testing on iOS and Android

    Description

    As a developer, I would like to do golden testing on iOS and Android

    Reasoning

    These are the platforms we target

    Additional context and comments

    We currently run golden testing on our pipelines but we cannot do golden testing on integration tests so we cannot test goldens on actual phones.

    We currently produce goldens with lots of different sizes with a Linux desktop. That's a problem because the pipeline goldens don't match our local goldens (Mac / windows). We have to do eleborate hacks just to incorporate goldens in our flow.

    We've done plenty of research on this and the only other way we can so this is to take literal screenshot and then do image compares ourself.

    If this library would allow us to do golden testing on integration tests, especially with Android and iOS, it would be a quantum leap forward for us and basically every flutter developer on the planet that does golden testing.

    Thanks

    opened by MelbourneDeveloper 6
  • fix!: load asset images for tests

    fix!: load asset images for tests

    Description

    Closes #16 .

    I also made a (breaking) refactor to use a builder instead of a widget, which should prevent state from being unintentionally maintained between the ci and platform test runs. Also, what do we think about including precacheImages in this package?

    Type of Change

    • [ ] ✨ New feature (non-breaking change which adds functionality)
    • [x] 🛠️ Bug fix (non-breaking change which fixes an issue)
    • [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change)
    • [x] 🧹 Code refactor
    • [ ] ✅ Build configuration change
    • [ ] 📝 Documentation
    • [ ] 🗑️ Chore
    opened by Kirpal 5
  • fix: runZoned / withClock not working

    fix: runZoned / withClock not working

    Is there an existing issue for this?

    • [X] I have searched the existing issues.

    Version

    0.5.1

    Description

    tl;dr What is the proper way to run a goldenTest in a Zone?

    I want to mock DateTime.now() and for this I use the offical "clock" package.

    Steps to reproduce

    withClock uses runZoned under the hood and can return the callback/ result so I thought it should be possible to put it in somewhere in "goldenTest" - I tried:

    builder: () => withClock<Widget>(
            Clock.fixed(DateTime(2022, 11, 17)),
            () => MyFancyWidget)
    
    pumpWidget: (tester, widget) async => withClock(
            Clock.fixed(DateTime(2022, 11, 17)),
            () async {
              await tester.pumpWidget(widget);
            },
          ),
    

    both did not work and the current dateTime was used instead, suggesting that for some reason the Zone was not used.

    Expected behavior

    I would expect both of the above examples to be valid.

    This is an example of how withClock is used in a basic unit test:

    test('returns a proper greeting on a Tuesday', () {
        final greeting = withClock(
          Clock.fixed(DateTime(2020, 09, 01)),
          () => Greeter().greet(),
        );
    
        expect(greeting, 'Happy Tuesday, you!');
    # example from: https://iiro.dev/controlling-time-with-package-clock/    
    

    Screenshots

    No response

    Additional context and comments

    So this all turns out to be a question of "What is the proper way to run a goldenTest in a Zone?"

    bug 
    opened by dkbast 2
  • fix: Dialog and dropdowns are no longer visible on the golden files

    fix: Dialog and dropdowns are no longer visible on the golden files

    Is there an existing issue for this?

    • [X] I have searched the existing issues.

    Version

    0.5.0

    Description

    After upgrading from version 0.3.3 to 0.5.0 the golden test stopped showing dialogs and opened dropdown menus. I have changed nothing with the pre test pumps, but still

    Steps to reproduce

    This is a test I wrote, trying to reproduce it:

    import 'package:alchemist/alchemist.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_test/flutter_test.dart';
    
    void main() {
      goldenTest(
        'drop down',
        fileName: 'dropdown',
        constraints: const BoxConstraints(
          maxWidth: 500,
          maxHeight: 500,
        ),
        pumpBeforeTest: (tester) async {
          await tester.pumpAndSettle();
          await tester.tap(find.byType(DropdownButton<String>));
          await tester.pumpAndSettle();
        },
        builder: () {
          return const TestApp();
        },
      );
    
      goldenTest(
        'dialog',
        fileName: 'dialog',
        constraints: const BoxConstraints(
          maxWidth: 500,
          maxHeight: 500,
        ),
        pumpBeforeTest: (tester) async {
          await tester.pumpAndSettle();
          await tester.tap(find.byType(TextButton));
          await tester.pumpAndSettle();
        },
        builder: () {
          return const TestApp();
        },
      );
    }
    
    class TestApp extends StatelessWidget {
      const TestApp({super.key});
    
      @override
      Widget build(BuildContext context) => Material(
            child: Center(
              child: Column(
                children: [
                  DropdownButton<String>(
                    value: '0',
                    items: const [
                      DropdownMenuItem<String>(
                        value: '0',
                        child: Text('0'),
                      ),
                      DropdownMenuItem<String>(
                        value: '1',
                        child: Text('1'),
                      ),
                      DropdownMenuItem<String>(
                        value: '2',
                        child: Text('2'),
                      ),
                    ],
                    onChanged: null,
                  ),
                  TextButton(
                    onPressed: () {
                      showDialog(
                        context: context,
                        builder: (context) => const AlertDialog(
                          content: Text('popup'),
                        ),
                      );
                    },
                    child: const Text('button'),
                  )
                ],
              ),
            ),
          );
    }
    

    This is the config setup:

    // flutter_test_config.dart
    
    import 'dart:async';
    import 'dart:io';
    
    import 'package:alchemist/alchemist.dart';
    import 'package:flutter/material.dart';
    
    Future<void> testExecutable(FutureOr<void> Function() testMain) async {
      // This is used to detect if it is running in a github actions workflow
      // For other CI Systems this might look different
      final isRunningInCi = Platform.environment['CI'] == 'true';
    
      return AlchemistConfig.runWithConfig(
        config: AlchemistConfig(
          theme: baseTheme.copyWith(textTheme: strippedTextTheme),
          platformGoldensConfig: PlatformGoldensConfig(
            enabled: !isRunningInCi,
          ),
        ),
        run: testMain,
      );
    }
    
    final baseTheme = ThemeData.light();
    final baseTextTheme = baseTheme.textTheme;
    
    final strippedTextTheme = baseTextTheme.copyWith(
      displayLarge: baseTextTheme.displayLarge?.forGoldens,
      displayMedium: baseTextTheme.displayMedium?.forGoldens,
      displaySmall: baseTextTheme.displaySmall?.forGoldens,
      headlineLarge: baseTextTheme.headlineLarge?.forGoldens,
      headlineMedium: baseTextTheme.headlineMedium?.forGoldens,
      headlineSmall: baseTextTheme.headlineSmall?.forGoldens,
      bodyLarge: baseTextTheme.bodyLarge?.forGoldens,
      bodyMedium: baseTextTheme.bodyMedium?.forGoldens,
      bodySmall: baseTextTheme.bodySmall?.forGoldens,
      titleLarge: baseTextTheme.titleLarge?.forGoldens,
      titleMedium: baseTextTheme.titleMedium?.forGoldens,
      titleSmall: baseTextTheme.titleSmall?.forGoldens,
      labelLarge: baseTextTheme.labelLarge?.forGoldens,
      labelMedium: baseTextTheme.labelMedium?.forGoldens,
      labelSmall: baseTextTheme.labelSmall?.forGoldens,
    );
    
    extension _GoldenTextStyle on TextStyle {
      TextStyle get forGoldens {
        final familySplit = fontFamily?.split('/');
        final rawFamily = familySplit?.last;
    
        return TextStyle(
          inherit: inherit,
          color: color,
          backgroundColor: backgroundColor,
          fontSize: fontSize,
          fontWeight: fontWeight,
          fontStyle: fontStyle,
          letterSpacing: letterSpacing,
          wordSpacing: wordSpacing,
          textBaseline: textBaseline,
          height: height,
          locale: locale,
          foreground: foreground,
          background: background,
          shadows: shadows,
          fontFeatures: fontFeatures,
          decoration: decoration,
          decorationColor: decorationColor,
          decorationStyle: decorationStyle,
          decorationThickness: decorationThickness,
          debugLabel: debugLabel,
          package: null,
          fontFamily: rawFamily,
          fontFamilyFallback: const ['Roboto'],
        );
      }
    }
    

    And these are the resulting images (for the ci):

    dialog dropdown

    Expected behavior

    The dropdown menu and dialog should be visable like in these screenshots generated with the 0.3.3 version (sadly due to the The non-abstract class 'BlockedTextCanvasAdapter' is missing implementations for these members error I can't produce these with the provided code, so I took the screenshot from our app):

    app-project-dialog projects-dropdown

    Screenshots

    No response

    Additional context and comments

    No response

    bug 
    opened by soeren-schmaljohann-2denker 1
  • fix: Huge memory consumption

    fix: Huge memory consumption

    Is there an existing issue for this?

    • [X] I have searched the existing issues.

    Version

    0.4.1

    Description

    Our app have many, many golden test like following. The issue is about memory consumption, we are today at 40go every run. Do you know what in golden test took so much memory ? Any general good practice ?

     goldenTest(
          'renders texts correctly',
          fileName:
              'theme-texts-${flavor.runtimeType.toString().toLowerCase()}-${mode.name}',
          builder: () => GoldenTestGroup(
            columns: 1,
            children: <GoldenTestScenario>[
              GoldenTestScenario(
                name: 'body text 1',
                child: Text(
                  'Sample text',
                  style: textTheme.bodyText1,
                ),
              ),
              GoldenTestScenario(
                name: 'body text 2',
                child: Text(
                  'Sample text',
                  style: textTheme.bodyText2,
                ),
              ),
              GoldenTestScenario(
                name: 'headline 1',
                child: Text(
                  'Sample text',
                  style: textTheme.headline1,
                ),
              ),
              GoldenTestScenario(
                name: 'headline 2',
                child: Text(
                  'Sample text',
                  style: textTheme.headline2,
                ),
              ),
              GoldenTestScenario(
                name: 'headline 3',
                child: Text(
                  'Sample text',
                  style: textTheme.headline3,
                ),
              ),
              GoldenTestScenario(
                name: 'headline 4',
                child: Text(
                  'Sample text',
                  style: textTheme.headline4,
                ),
              ),
              GoldenTestScenario(
                name: 'headline 5',
                child: Text(
                  'Sample text',
                  style: textTheme.headline5,
                ),
              ),
              GoldenTestScenario(
                name: 'headline 6',
                child: Text(
                  'Sample text',
                  style: textTheme.headline6,
                ),
              ),
              GoldenTestScenario(
                name: 'subtitle 1',
                child: Text(
                  'Sample text',
                  style: textTheme.subtitle1,
                ),
              ),
              GoldenTestScenario(
                name: 'subtitle 2',
                child: Text(
                  'Sample text',
                  style: textTheme.subtitle2,
                ),
              ),
            ],
          ),
        );
    
    Capture d’écran 2022-08-31 à 15 54 02

    Steps to reproduce

    run many golden test

    Expected behavior

    As less memory as possible

    Screenshots

    No response

    Additional context and comments

    No response

    bug 
    opened by EArminjon 6
  • fix: Svg pictures aren't rendered in CI mode

    fix: Svg pictures aren't rendered in CI mode

    Is there an existing issue for this?

    • [X] I have searched the existing issues.

    Version

    0.4.1

    Description

    Svg pictures aren't rendered correctly in CI mode. They work fine in macOS, but once you fit them with widgets with size below them they appear weirdly.

    I'm using flutter_svg: 1.1.4

    Steps to reproduce

    1. Create a golden test with this widget:
    Scaffold(
      body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            SvgPicture.asset(
              R.ILLUSTRATIONS_GENERIC_ERROR,
              fit: BoxFit.fitWidth,
            ),
            const SizedBox(height: 84),
          ],
      ),
    );
    
    1. Run flutter test --update-goldens - when you open the generated image that's the effect: comments_page_error

    I've also attached the svg picture I'm generating the svg with. generic_error

    Expected behavior

    The generated golden should be identical to macOS one. comments_page_error

    Screenshots

    No response

    Additional context and comments

    I'm using flutter 3.0.5

    bug 
    opened by mhnowak 3
  • fix: Reset pixel ratio and textScaleFactor values on tearDown

    fix: Reset pixel ratio and textScaleFactor values on tearDown

    Is there an existing issue for this?

    • [X] I have searched the existing issues.

    Version

    0.4.1

    Description

    The method FlutterGoldenTestAdapter.pumpGoldenTest sets a new pixelRatio and textScalorFactor test values that are not reset to the original values on tear down. This makes the test that run after a golden test to have modified properties that can alter the result of the test.

    https://github.com/Betterment/alchemist/blob/a80c62c94110e2d63defe19e11a7ec6d91347e26/lib/src/golden_test_adapter.dart#L226-L228

    We should clear values on tearDown:

    addTearDown(() {
       tester.binding.window.clearDevicePixelRatioTestValue();
       tester.binding.platformDispatcher.clearTextScaleFactorTestValue();
    });
    

    Steps to reproduce

    When running the following code, goldenTest sets up a new devicePixelRatio and the test after it fail.

    import 'package:alchemist/alchemist.dart';
    import 'package:flutter/widgets.dart';
    import 'package:flutter_test/flutter_test.dart';
    
    void main() {
      testWidgets('before golden devicePixelRatio', (tester) async {
        expect(tester.binding.window.devicePixelRatio, 3);
      });
    
      goldenTest(
        'A',
        fileName: 'a',
        builder: () => Container(height: 300),
      );
    
      testWidgets('after golden devicePixelRatio', (tester) async {
        expect(tester.binding.window.devicePixelRatio, 3);  // Fails with actual value 1
      });
    }
    

    Expected behavior

    When clearing devicePixelRatio on tearDown, the test work as expected

    import 'package:alchemist/alchemist.dart';
    import 'package:flutter/widgets.dart';
    import 'package:flutter_test/flutter_test.dart';
    
    void main() {
      testWidgets('before golden devicePixelRatio', (tester) async {
        expect(tester.binding.window.devicePixelRatio, 3);
      });
    
      goldenTest(
        'A',
        fileName: 'a',
        builder: () => Container(height: 300),
        whilePerforming: (tester) async {
          addTearDown(() {
            tester.binding.window.clearDevicePixelRatioTestValue();
          });
          return;
        },
      );
    
      testWidgets('after golden devicePixelRatio', (tester) async {
        expect(tester.binding.window.devicePixelRatio, 3);
      });
    }
    

    Screenshots

    Screenshot 2022-08-02 at 10 42 10

    Additional context and comments

    No response

    bug 
    opened by jamesblasco 1
  • request: run goldens with multiple configurations

    request: run goldens with multiple configurations

    Is there an existing feature request for this?

    • [X] I have searched the existing issues.

    Command

    I would love if we could specify a configuration (or more) per test

    Description

    As a developer, I would like to be able to only have to write a single goldenTest and be able to specify multiple configuration where the test would run.

    For example:

    goldenTest('foo', configuration: config1, ...);
    

    I would expect that if the configuration parameter is not required the global configuration is used (if any) instead. Hence, once the test finishes the global configuration is restored. I would also expect, to be able to give the Configuration some kind of parameter in order if the null properties should be inherited.

    The above is just an example. I'm not sure if it is to be considered the best API. Alternatives, could be, for example, to have a configurations be a List and avoid extracting the test method in order to reuse it. Or another possibility is to have a GoldenTestConfiguration widget:

    class GoldenTestConfiguration extends StatelessWidget {
      const GoldenTestConfiguration({
        super.key,
        required this.config,
        required this.child,
        this.inheritConfig = true,
      });
    
      final AlchemistConfig config;
    
      final bool inheritConfig;
    
      final Widget child;
    
      @override
      Widget build(BuildContext context) {
        return AlchemistConfig.runWithConfig<Widget>(
          config: inheritConfig ? AlchemistConfig.current().merge(config) : config,
          run: () => child,
        );
      }
    }
    
    // Or with a widget builder
    class GoldenTestConfiguration extends StatelessWidget {
      const GoldenTestConfiguration({
        super.key,
        required this.config,
        required this.builder,
        this.inheritConfig = true,
      });
    
      final AlchemistConfig config;
    
      final bool inheritConfig;
    
      final WidgetBuilder builder;
    
      @override
      Widget build(BuildContext context) {
        return AlchemistConfig.runWithConfig<Widget>(
          config: inheritConfig ? AlchemistConfig.current().merge(config) : config,
          run: () => builder(context),
        );
      }
    }
    
    

    --

    I'm unsure if having logic within setUp and tearDown that alters the config (similar to the snippet below) would work; but if so, I think it feels very verbose in comparison with just providing the configuration to goldenTest.

      AlchemistConfig.runWithConfig(
        config: AlchemistConfig(
          forceUpdateGoldenFiles: true,
        ),
        run: () {
          // test here.
        },
      );
    

    Reasoning

    In some scenarios, a developer would like to specify more than a single configuration. This could be motivated, for example, when there are different functionalities to be run when a given flavour or target is given. Hence, as a developer you would be interested on running the same test with different configurations.

    Example 1 You have different themes for different platforms and you wish to have a config with each theme. Currently the flutter_test_config.dart file looks like the above snippet. This is similar to #21 .

    // flutter_test_config.dart
    Future<void> testExecutable(FutureOr<void> Function() testMain) async {
      final enablePlatformTests =
          !Platform.environment.containsKey('GITHUB_ACTIONS');
    
      return AlchemistConfig.runWithConfig(
        config: AlchemistConfig(
          theme: AppTheme(platform: TargetPlatform.android).themeData,
          platformGoldensConfig:
              AlchemistConfig.current().platformGoldensConfig.copyWith(
                    enabled: enablePlatformTests,
                  ),
        ),
        run: testMain,
      );
    }
    

    Additional context and comments

    N/A

    opened by alestiago 1
Releases(v0.6.0-dev.1)
  • v0.6.0-dev.1(Nov 16, 2022)

    What's Changed

    • chore: upgrade flutter to beta version by @Kirpal in https://github.com/Betterment/alchemist/pull/84

    Full Changelog: https://github.com/Betterment/alchemist/compare/v0.5.1...v0.6.0-dev.1

    Source code(tar.gz)
    Source code(zip)
  • v0.5.1(Oct 31, 2022)

    What's Changed

    • fix: ensure that error messages are always legible by @Kirpal in https://github.com/Betterment/alchemist/pull/78
    • fix: properly clear window size overrides after test run by @Kirpal in https://github.com/Betterment/alchemist/pull/81
    • chore: v0.5.1 by @Kirpal in https://github.com/Betterment/alchemist/pull/82

    Full Changelog: https://github.com/Betterment/alchemist/compare/v0.5.0...v0.5.1

    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(Sep 7, 2022)

    What's Changed

    • chore: upgrade to flutter 3.3.0 by @Kirpal in https://github.com/Betterment/alchemist/pull/75
    • chore: v0.5.0 by @Kirpal in https://github.com/Betterment/alchemist/pull/77

    Full Changelog: https://github.com/Betterment/alchemist/compare/v0.4.1...v0.5.0

    Source code(tar.gz)
    Source code(zip)
  • v0.4.1(Jul 20, 2022)

    What's Changed

    • chore: downgrade min sdk to 2.16.2 by @Kirpal in https://github.com/Betterment/alchemist/pull/69
    • chore: v0.4.1 by @Kirpal in https://github.com/Betterment/alchemist/pull/70

    Full Changelog: https://github.com/Betterment/alchemist/compare/v0.4.0...v0.4.1

    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Jul 20, 2022)

    What's Changed

    • ci: fix the title of the semantic PR job by @btrautmann in https://github.com/Betterment/alchemist/pull/48
    • chore: upgrade to flutter 3.0.0 by @marcossevilla in https://github.com/Betterment/alchemist/pull/51
    • chore: upgrade to very_good_analysis 3.0.0 by @marcossevilla in https://github.com/Betterment/alchemist/pull/52
    • docs: update simulating gestures snippet by @marcossevilla in https://github.com/Betterment/alchemist/pull/54
    • fix: load fonts from other packages correctly by @jeroen-meijer in https://github.com/Betterment/alchemist/pull/55
    • fix: fix nested MaterialApp-related issues (l10n, theming) by @jeroen-meijer in https://github.com/Betterment/alchemist/pull/60
    • feat: add improved example project by @jeroen-meijer in https://github.com/Betterment/alchemist/pull/57
    • ci: add workflow that will upload code coverage after a merge to main by @btrautmann in https://github.com/Betterment/alchemist/pull/65
    • feat: add constraints to golden test group and scenario by @Kirpal in https://github.com/Betterment/alchemist/pull/59
    • fix: add default localizations by @Kirpal in https://github.com/Betterment/alchemist/pull/68
    • chore: v0.4.0 by @marcossevilla in https://github.com/Betterment/alchemist/pull/53

    New Contributors

    • @jeroen-meijer made their first contribution in https://github.com/Betterment/alchemist/pull/55

    Full Changelog: https://github.com/Betterment/alchemist/compare/v0.3.3...v0.4.0

    Source code(tar.gz)
    Source code(zip)
  • v0.3.3(Apr 25, 2022)

    What's Changed

    • chore: Update example to use builder by @hawkbee1 in https://github.com/Betterment/alchemist/pull/38
    • chore: Fix repo links in README by @defuncart in https://github.com/Betterment/alchemist/pull/41
    • fix: Use home instead of builder when pumpWidget in GoldenTestAdapter.pumpGoldenTest by @HevaWu in https://github.com/Betterment/alchemist/pull/42
    • ci: use semantic-pull-request github action over semantic-pull-requests app by @btrautmann in https://github.com/Betterment/alchemist/pull/46
    • chore: upgrade flutter to 2.10.4 by @marcossevilla in https://github.com/Betterment/alchemist/pull/45
    • chore: v0.3.3 by @marcossevilla in https://github.com/Betterment/alchemist/pull/47

    New Contributors

    • @hawkbee1 made their first contribution in https://github.com/Betterment/alchemist/pull/38
    • @defuncart made their first contribution in https://github.com/Betterment/alchemist/pull/41
    • @HevaWu made their first contribution in https://github.com/Betterment/alchemist/pull/42

    Full Changelog: https://github.com/Betterment/alchemist/compare/v0.3.2...v0.3.3

    Source code(tar.gz)
    Source code(zip)
  • v0.3.2(Mar 18, 2022)

    What's Changed

    • feat: add pumpWidget callback to goldenTest by @marcossevilla in https://github.com/Betterment/alchemist/pull/34
    • feat: add scroll interaction by @marcossevilla in https://github.com/Betterment/alchemist/pull/36

    Full Changelog: https://github.com/Betterment/alchemist/compare/v0.3.1...v0.3.2

    Source code(tar.gz)
    Source code(zip)
  • v0.3.1(Mar 14, 2022)

    What's Changed

    • feat: export test asset bundle by @marcossevilla in https://github.com/Betterment/alchemist/pull/32

    New Contributors

    • @marcossevilla made their first contribution in https://github.com/Betterment/alchemist/pull/32

    Full Changelog: https://github.com/Betterment/alchemist/compare/v0.3.0...v0.3.1

    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Mar 10, 2022)

    What's Changed

    • chore: remove dependabot by @CelticMajora in https://github.com/Betterment/alchemist/pull/22
    • feat!: Improve reliability, add unit tests by @definitelyokay in https://github.com/Betterment/alchemist/pull/19
    • fix: CI tests fail when using CompositedTransformFollower by @Kirpal in https://github.com/Betterment/alchemist/pull/24
    • ci: use codecov instead of lcov reporter by @Kirpal in https://github.com/Betterment/alchemist/pull/26
    • feat: renderShadows flag by @Giuspepe in https://github.com/Betterment/alchemist/pull/20
    • chore: add brandon, marcos, and joanna to codeowners by @samandmoore in https://github.com/Betterment/alchemist/pull/27
    • fix!: load asset images for tests by @Kirpal in https://github.com/Betterment/alchemist/pull/25
    • chore: remove duplicate vgv logos by @Kirpal in https://github.com/Betterment/alchemist/pull/28
    • docs: update readme by @Kirpal in https://github.com/Betterment/alchemist/pull/29

    New Contributors

    • @Giuspepe made their first contribution in https://github.com/Betterment/alchemist/pull/20
    • @samandmoore made their first contribution in https://github.com/Betterment/alchemist/pull/27

    Full Changelog: https://github.com/Betterment/alchemist/compare/v0.2.1...v0.3.0

    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Feb 23, 2022)

    What's Changed

    • chore: Remove docs depicting placeholders by @definitelyokay in https://github.com/Betterment/alchemist/pull/1
    • fix: use blocked text for all render objects by @Kirpal in https://github.com/Betterment/alchemist/pull/3
    • chore: Various cleanups I saw by @CelticMajora in https://github.com/Betterment/alchemist/pull/2
    • chore: Add dependabot to keep github actions up-to-date by @CelticMajora in https://github.com/Betterment/alchemist/pull/5
    • chore: Additional cleanups by @definitelyokay in https://github.com/Betterment/alchemist/pull/4
    • feat: Add generic interactions by @definitelyokay in https://github.com/Betterment/alchemist/pull/6
    • chore: Fix publish dry run issues by @definitelyokay in https://github.com/Betterment/alchemist/pull/8
    • fix(readme): Update README.md to fix pub link by @btrautmann in https://github.com/Betterment/alchemist/pull/9
    • chore: Bump version, remove explicit test version by @definitelyokay in https://github.com/Betterment/alchemist/pull/10
    • chore: Fix link by @definitelyokay in https://github.com/Betterment/alchemist/pull/12
    • docs: Update changelog by @definitelyokay in https://github.com/Betterment/alchemist/pull/13

    New Contributors

    • @definitelyokay made their first contribution in https://github.com/Betterment/alchemist/pull/1
    • @Kirpal made their first contribution in https://github.com/Betterment/alchemist/pull/3
    • @CelticMajora made their first contribution in https://github.com/Betterment/alchemist/pull/2
    • @btrautmann made their first contribution in https://github.com/Betterment/alchemist/pull/9

    Full Changelog: https://github.com/Betterment/alchemist/commits/v0.2.1

    Source code(tar.gz)
    Source code(zip)
Owner
Betterment
We're passionate about building the simplest, most sophisticated investment platform on the planet. Visit us at www.betterment.com/jobs.
Betterment
A better font for golden tests.

A better font for golden tests. This project is a Flutter Bounty Hunters proof-of-concept. Want font adjustments? Fund a milestone today! Golden Brick

Flutter Bounty Hunters 3 Dec 14, 2022
Simple and complete Flutter hooks testing utilities that encourage good testing practices.

Flutter Hooks Testing Library Simple and complete Flutter hooks testing utilities that encourage good testing practices. Inspired by react-hooks-testi

Daichi Furiya 24 Dec 2, 2022
Dart JS interop for Mermaid - The Javascript tool that makes use of a markdown based syntax to render customizable diagrams, charts and visualizations.

Mermaid (Dart) Dart JS interop for Mermaid - Javascript library that makes use of a markdown based syntax to render customizable diagrams, charts and

Tim Maffett 3 Dec 12, 2022
This is tool to create 3D Models which can be used in Flutter Applications. Tool is developed completely using Flutter.

three_d_model_tool A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you start

Shubham Yeole 2 Nov 8, 2022
Flutter makes it easy and fast to build beautiful apps for mobile and beyond

Flutter is Google's SDK for crafting beautiful, fast user experiences for mobile, web, and desktop from a single codebase. Flutter works with existing

Flutter 148.2k Jan 8, 2023
🙌🏾 This package makes it easy to use the Mono connect widget in a flutter project

Flutter Mono ** This is an unofficial SDK for flutter This package makes it easy to use the Mono connect widget in a flutter project. ?? Screen Shots

Chiziaruhoma Ogbonda 12 Dec 20, 2022
flutter_thrio makes it easy and fast to add flutter to existing mobile applications, and provide a simple and consistent navigator APIs.

中文文档 英文文档 问题集 原仓库不再维护,代码已经很老了 最近版本更新会很快,主要是增加新特性,涉及到混合栈的稳定性的问题应该不多,可放心升级,发现问题加 QQ 群号码:1014085473,我会尽快解决。 不打算好好看看源码的使用者可以放弃这个库了,因为很多设定是比较死的,而我本人不打算花时间写

null 290 Dec 29, 2022
flutter_thrio makes it easy and fast to add flutter to existing mobile applications, and provide a simple and consistent navigator APIs.

本仓库不再维护,可移步新仓库 https://github.com/flutter-thrio/flutter_thrio 中文文档 问题集 QQ 群号码:1014085473 The Navigator for iOS, Android, Flutter. Version 0.2.2 requir

Hellobike 732 Dec 5, 2022
This library provides a customizable Flutter widget that makes it easy to display text in the middle of a Divider.

1. About 1.1. Introduction 1.1.1. Install Library 1.1.2. Import It 1.1.3. Use TextDivider 1.2. Details 1.2.1. Customization Options 1.2.2. Horizontal

Kato Shinya 2 Feb 9, 2022
A library that makes it easy for you to create your own custom wizard.

Flutter Wizard Author: Jop Middelkamp A library that makes it easy for you to create your custom wizard. You'll have 100% control over the appearance

Baseflow 13 Dec 2, 2022
Nexus is a state management library that makes it easy to create and consume your application's reactive data to the user interface.

Nexus ?? Nexus is a state management library that makes it easy to create and consume your application's reactive data to the user interface. With nex

Gor Mkhitaryan 3 Sep 7, 2022
The flutter_ibm_watson makes it easy to integrate IBM Watson

Flutter Ibm Watson Installation Add this to your package's pubspec.yaml file: dependencies: flutter_ibm_watson: ^0.0.1 You can install packages fro

Victor Alfonso Rodas Oña 27 Nov 4, 2022
Dart package to which makes data communication easy among different modules of your application.

LiveStream - Dart LiveStream is a data holder class which can observe change of data in real-time and emit values too. Here's emitter subscriber patte

Shreyas Patil 75 Sep 28, 2022
Toor makes service locators compile-time safe and easy to manage

?? What is Toor Toor makes service locators compile-time safe and easy to manage. ?? Getting Started Define your dependencies somewhere in the project

Arshak Aghakaryan 5 Jul 25, 2022
A very easy-to-use navigation tool/widget for having iOS 13 style stacks.

cupertino_stackview A very easy-to-use navigation tool/widget for having iOS 13 style stacks. It is highly recommended to read the documentation and r

AliYigitBireroglu 49 Nov 18, 2022
Bilgi Testi Flutter - A knowledge testing app built with Flutter

Bilgi Testi 7 sorudan oluşan puanlama mekaniği olan, modern tasarımlı, flutter i

null 0 Feb 9, 2022
Flutter_news - News application developed for practice, learning and testing the potential of this powerful Framework Flutter

flutter_news News application developed for practice, learning and testing the potential of this powerful Google's UI toolkit. Resources Packages pub

Rafael Almeida Barbosa 487 Dec 17, 2022
Spec - A streamlined testing framework for Dart & Flutter

✅ Spec A streamlined testing framework for Dart & Flutter. What is it? Spec buil

Invertase 278 Dec 22, 2022