Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Conversation

@nturgut
Copy link
Contributor

@nturgut nturgut commented Aug 1, 2020

Description

Adding capability to e2e to take screenshot for web tests. This infrastructure can also be used for triggering other WebDriver actions such as resize, back, forward. (https://www.w3.org/TR/webdriver/#endpoints)

Manually tested on Chrome, Firefox, Safari and Ios-Safari.

e2e_driver_extended.dart is only to be used as an example. We will use Flutter Gold to do the matching goldens for Flutter for Web integration tests.

Related Issues

flutter/flutter#51890
flutter/flutter#62706

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • My PR includes unit or integration tests for all changed/updated/fixed behaviors (See [Contributor Guide]).
  • All existing and new tests are passing.
  • I updated/added relevant documentation (doc comments with ///).
  • The analyzer (flutter analyze) does not report any problems on my PR.
  • I read and followed the [Flutter Style Guide].
  • The title of the PR starts with the name of the plugin surrounded by square brackets, e.g. [shared_preferences]
  • I updated pubspec.yaml with an appropriate new version according to the [pub versioning philosophy].
  • I updated CHANGELOG.md to add a description of the change.
  • I signed the [CLA].
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Does your PR require plugin users to manually update their apps to accommodate your change?

  • Yes, this is a breaking change (please indicate a breaking change in CHANGELOG.md and increment major revision).
  • No, this is not a breaking change.

await _webDriverCommand(WebDriverAction.screenshot(screenshot_name));
}

Future<void> _webDriverCommand(WebDriverAction command) async {
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this go in a web-specific implementation file, and we'd have another implementation file for IO, so we just call the method (or instantiate the class) and the VM version just throws for now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I carried the webdriver specific logic to another file. Please have another look.

Map<String, String> params) async {
final String command = params['command'];
// Test status is added as an exta message.
final String extraMessage = params['message'] ?? '';
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have this documented anywhere?

Would we be better off implementing some serialized type for this that could more clearly be used on both sides of the message?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can add a string to the requestData call for managing generic communication. Documentation is here: https://github.com/flutter/flutter/blob/master/packages/flutter_driver/lib/src/driver/driver.dart#L494

Are you recommending to use another command other than RequestData. I think that would make the handshake more complicated.

// Test status is added as an exta message.
final String extraMessage = params['message'] ?? '';
Map<String, String> response;
switch (command) {
Copy link
Contributor

Choose a reason for hiding this comment

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

IOW, can we avoid having this switch statement that will continue to grow, with nested ifs underneath that will get harder to reason about?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I refactored the methods and separated the part for request_data into 2 methods. I hope it looks more readable now. PHAL.

} else {
// If Test status is `wait_on_webdriver_command` send the first
// command in the `commandPipe` to the tests.
if (extraMessage == '${TestStatus.wait_on_webdriver_command}') {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why would the driving script do this? Shouldn't the test itself be awaiting whatever it needs (i.e. taking the screenshot), and the driving script just waits for the test reporting to finish?

Another way of putting this concern: how does the caller know which web driver command(s) it's waiting on, that there won't be another one it's actually interested in coming right after the one it just waited on?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why would the driving script do this? Shouldn't the test itself be awaiting whatever it needs (i.e. taking the screenshot), and the driving script just waits for the test reporting to finish?

Only driver script can take screenshots. Almost all browsers implements the webdriver API which allows us to take screenshot. We can also extend this to do other import things such as changing screensize, contorrling cookies: https://www.w3.org/TR/webdriver1/. Since only driver test can perform these operations, we developed this handshake mechanism between the integration_test and the driver test.

In summary: We are sending the request from the integration_test (ex: WebDriverActionTypes.screenshot), waiting on the result from the driver. If there are multiple test methods which are asking for a WebDriverAction, they wait on the mutex, driver handles them one by one.

Another way of putting this concern: how does the caller know which web driver command(s) it's waiting on, that there won't be another one it's actually interested in coming right after the one it just waited on?

That is why I used a synchronization method (such as mutex) to send these requests to driver one at a time. I tested with many scenarios:

  1. requests in within different methods.
  2. few request in a few methods.
  3. Failing vs passing tests in different methods.

This handshake approach worked well.

@nturgut nturgut force-pushed the web_screenshots branch 2 times, most recently from 0f41cff to 4562479 Compare August 24, 2020 20:12
@nturgut nturgut requested review from dnfield and yjbanov August 24, 2020 20:17
Copy link
Contributor

@dnfield dnfield left a comment

Choose a reason for hiding this comment

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

LGTM, would appreciate review from @yjbanov for web/driver related code.

Copy link
Contributor

@yjbanov yjbanov left a comment

Choose a reason for hiding this comment

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

LGTM if LGT @dnfield

// Trigger a frame.
await tester.pumpAndSettle();

// TODO: Add screenshot capability for mobile platforms.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: link this to the screenshot bug.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

is there an issue for it for mobile? or should I use the existing issue?

Copy link
Contributor

Choose a reason for hiding this comment

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

Just use the existing one.

Copy link
Contributor

@dnfield dnfield left a comment

Choose a reason for hiding this comment

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

Please remove the .png files, and consider updating the .gitignore for that.

@nturgut
Copy link
Contributor Author

nturgut commented Aug 28, 2020

Please remove the .png files, and consider updating the .gitignore for that.

done. thanks for noticing :)

Copy link
Contributor

@dnfield dnfield left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@digiter digiter left a comment

Choose a reason for hiding this comment

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

LGTM

@ditman
Copy link
Member

ditman commented Aug 31, 2020

I'm investigating the current breakages of the CI, and they don't seem related to any changes in the flutter/plugins repo (but a change in the engine), so if you need to merge this on red, go ahead!

@nturgut
Copy link
Contributor Author

nturgut commented Aug 31, 2020

I'm investigating the current breakages of the CI, and they don't seem related to any changes in the flutter/plugins repo (but a change in the engine), so if you need to merge this on red, go ahead!

thanks a lot for investigating :)

@nturgut nturgut merged commit ce2c155 into flutter:master Aug 31, 2020
jorgefspereira pushed a commit to jorgefspereira/plugins_flutter that referenced this pull request Oct 10, 2020
…tter#2904)

* screenshot taking works

* squash commits. addressing reviewer comments. making drivercommandmanager->callback manager

* addressing reviewer comment. mostly name changes

* major rename on all files webdriveraction->webdrivercommand

* remove files. use implements

* remove timeout. add onScreenshot callback

* remove remaning timeouts. add an error message for screenshots. use an object instead of strings for status messages

* created a new issue

* remove example screenshot saving since it's failing on android. examples in integration_test package is common

* changing the version and the change log
FlutterSu pushed a commit to FlutterSu/flutter-plugins that referenced this pull request Nov 20, 2020
…tter#2904)

* screenshot taking works

* squash commits. addressing reviewer comments. making drivercommandmanager->callback manager

* addressing reviewer comment. mostly name changes

* major rename on all files webdriveraction->webdrivercommand

* remove files. use implements

* remove timeout. add onScreenshot callback

* remove remaning timeouts. add an error message for screenshots. use an object instead of strings for status messages

* created a new issue

* remove example screenshot saving since it's failing on android. examples in integration_test package is common

* changing the version and the change log
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants