Skip to content

Conversation

@AsCress
Copy link
Collaborator

@AsCress AsCress commented Aug 17, 2025

Fixes #2842.
Adds an integration test covering the app flow, also used to obtain screenshots.
More specifically, this PR:

  1. Adds an integration test that moves through various instruments capturing screenshots. This would be running on every push and pull request to capture the latest screenshots in the future.
  2. Adds relevant keys for identifying elements.
  3. Fixes all the errors that caused the integration test to fail.

Screenshots / Recordings

Complete run of the test:
https://www.loom.com/share/e7896865513d4a11a8d308dff68f0b9a?sid=5ac03f8f-713a-4e4a-8510-3d6a000da1f3

Summary by Sourcery

Add a full app end-to-end integration test suite with screenshot capture, instrument screen key identifiers, and supporting fixes for data initialization, permissions, and localization to ensure test stability

New Features:

  • Add end-to-end integration tests that navigate through all instrument screens and capture screenshots

Bug Fixes:

  • Initialize accelerometer data lists with a default point to prevent empty-chart errors

Enhancements:

  • Introduce unique widget keys for each instrument screen title to aid test element lookup
  • Request microphone permission when switching to the built-in MIC in channel parameters
  • Add and de-duplicate localization getters for 'sharingMessage' and 'delete'

Build:

  • Add the integration_test package to dev_dependencies

Tests:

  • Add integration test files (screenshots.dart, utils.dart, test_driver.dart) and helper utilities for screenshot capture

@AsCress AsCress self-assigned this Aug 17, 2025
@AsCress AsCress added Feature New addition to the existing app flutter labels Aug 17, 2025
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Aug 17, 2025

Reviewer's Guide

This PR establishes an end-to-end integration test suite that traverses the core app flow to capture up‐to‐date screenshots, introduces unique keys for reliable UI element identification, cleans up localization definitions, refactors scaffold key handling, and patches data initialization and permission flows to ensure test stability.

Entity relationship diagram for new instrument screen keys

erDiagram
  INSTRUMENTS_SCREEN {
    string instrumentsScreenTitleKey
  }
  ACCELEROMETER_SCREEN {
    string accelerometerScreenTitleKey
  }
  MULTIMETER_SCREEN {
    string multimeterScreenTitleKey
  }
  WAVE_GENERATOR_SCREEN {
    string waveGeneratorScreenTitleKey
  }
  OSCILLOSCOPE_SCREEN {
    string oscilloscopeScreenTitleKey
  }
  POWER_SOURCE_SCREEN {
    string powerSourceScreenTitleKey
  }
  INSTRUMENTS_SCREEN ||--|| ACCELEROMETER_SCREEN : identifies
  INSTRUMENTS_SCREEN ||--|| MULTIMETER_SCREEN : identifies
  INSTRUMENTS_SCREEN ||--|| WAVE_GENERATOR_SCREEN : identifies
  INSTRUMENTS_SCREEN ||--|| OSCILLOSCOPE_SCREEN : identifies
  INSTRUMENTS_SCREEN ||--|| POWER_SOURCE_SCREEN : identifies
Loading

Class diagram for updated AccelerometerStateProvider data initialization

classDiagram
  class AccelerometerStateProvider {
    - List<double> _xData
    - List<double> _yData
    - List<double> _zData
    + List<FlSpot> xData = [FlSpot(0, 0)]
    + List<FlSpot> yData = [FlSpot(0, 0)]
    + List<FlSpot> zData = [FlSpot(0, 0)]
    - int _maxLength
    - double _xMin
    - double _xMax
  }
Loading

Class diagram for MainScaffoldWidget scaffold key refactor

classDiagram
  class MainScaffold {
    + Key? scaffoldKey
    + String title
  }
  class _MainScaffoldState {
    + build()
  }
  MainScaffold <|-- _MainScaffoldState
Loading

File-Level Changes

Change Details Files
Integration test infrastructure and E2E flow with screenshot capture
  • Add integration_test to dev_dependencies
  • Create integration test that navigates through instruments and captures screenshots
  • Implement pumpUntilFound utility to await element visibility
  • Configure test_driver to save screenshots per device with custom naming
pubspec.yaml
test_integration/screenshots.dart
test_integration/utils.dart
test_integration/test_driver.dart
UI identification via constants and scaffold key refactor
  • Define screen title Key constants
  • Import and apply Key constants to each CommonScaffold instance
  • Refactor MainScaffold to accept a scaffoldKey instead of generating a ValueKey
  • Remove hardcoded permission request in instruments screen init
lib/constants.dart
lib/view/accelerometer_screen.dart
lib/view/instruments_screen.dart
lib/view/multimeter_screen.dart
lib/view/oscilloscope_screen.dart
lib/view/power_source_screen.dart
lib/view/wave_generator_screen.dart
lib/view/widgets/main_scaffold_widget.dart
Localization entries cleanup and repositioning
  • Remove duplicate getters for sharingMessage and delete
  • Relocate sharingMessage and delete definitions to the correct section
  • Update English translations accordingly
lib/l10n/app_localizations.dart
lib/l10n/app_localizations_en.dart
Fixes to support integration test stability (data seeding and permissions)
  • Seed accelerometer FlSpot lists with an initial value to prevent empty graph errors
  • Request microphone permission within channel parameter change handler
  • Remove redundant permission request from instruments screen init
lib/providers/accelerometer_state_provider.dart
lib/view/widgets/channel_parameters_widget.dart
lib/view/instruments_screen.dart

Assessment against linked issues

Issue Objective Addressed Explanation
#2842 Add an integration test that explores the complete app flow.
#2842 Ensure the integration test captures screenshots during the app flow.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • Replace the multiple fixed-duration pumps (e.g. pump(const Duration(seconds: 5))) with event-driven waits or reuse pumpUntilFound to make the integration test faster and more reliable.
  • Inject or mock the microphone permission request in tests (instead of real Permission.microphone.request()) to avoid system dialogs blocking the CI run.
  • Use the localized string for the oscilloscope title rather than a hard-coded 'Oscilloscope' literal to keep titles consistent and localizable.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Replace the multiple fixed-duration pumps (e.g. pump(const Duration(seconds: 5))) with event-driven waits or reuse pumpUntilFound to make the integration test faster and more reliable.
- Inject or mock the microphone permission request in tests (instead of real Permission.microphone.request()) to avoid system dialogs blocking the CI run.
- Use the localized string for the oscilloscope title rather than a hard-coded 'Oscilloscope' literal to keep titles consistent and localizable.

## Individual Comments

### Comment 1
<location> `lib/providers/accelerometer_state_provider.dart:18` </location>
<code_context>
-  final List<FlSpot> xData = [];
-  final List<FlSpot> yData = [];
-  final List<FlSpot> zData = [];
+  final List<FlSpot> xData = [const FlSpot(0, 0)];
+  final List<FlSpot> yData = [const FlSpot(0, 0)];
+  final List<FlSpot> zData = [const FlSpot(0, 0)];

   final int _maxLength = 50;
</code_context>

<issue_to_address>
Initializing xData, yData, and zData with a default value may affect chart rendering.

Initializing with FlSpot(0, 0) may cause an unintended data point to appear. If this is not desired, use empty lists and update your chart to handle cases with no data.

Suggested implementation:

```
  final List<FlSpot> xData = [];
  final List<FlSpot> yData = [];
  final List<FlSpot> zData = [];

```

You should review the chart rendering logic to ensure it does not fail or display incorrectly when these lists are empty. For example, you may need to add checks to avoid rendering the chart or show a placeholder when there is no data.
</issue_to_address>

### Comment 2
<location> `lib/view/widgets/channel_parameters_widget.dart:250` </location>
<code_context>
                       groupValue:
                           oscilloscopeStateProvider.isInBuiltMICSelected,
-                      onChanged: (bool? value) {
+                      onChanged: (bool? value) async {
+                        await Permission.microphone.request();
                         setState(
                           () {
</code_context>

<issue_to_address>
Requesting microphone permission on every RadioGroup change may be redundant.

Repeatedly requesting microphone permission on every radio button change can disrupt the user experience. Only request permission when the microphone option is selected and permission hasn't been granted yet.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@github-actions
Copy link
Contributor

github-actions bot commented Aug 17, 2025

@marcnause marcnause enabled auto-merge (squash) August 19, 2025 17:05
@AsCress AsCress force-pushed the integration_tests branch from ed1401f to 954bb50 Compare August 19, 2025 17:45
@marcnause marcnause merged commit 1cb5b77 into fossasia:flutter Aug 19, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature New addition to the existing app flutter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add integration tests

2 participants