Skip to content

fix: add support for non-root base-href #75

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 23 commits into
base: main
Choose a base branch
from

Conversation

holzgeist
Copy link

Description

if a web-app is deployed using --base-href=/path/to/deployed/flutter/app during build, the URLs starting with ./assets won't work anymore. Using assetManager will properly resolve them. It uses assetBase from the loader config specified here

NB ⚠️

I only tested the url.startsWith('assets/') code path as it's the only one used in the library. It should work the same for ./ though

if a web-app is deployed using `--base-href` during build, the URLs
starting with `./assets` won't work anymore. Use `assetManager` to
properly resolve them
Copy link
Collaborator

@diegotori diegotori left a comment

Choose a reason for hiding this comment

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

@holzgeist Before I run the workflow, there is one thing that I need you to do.

In other words, we need to move assets/no_sleep.js into the lib folder as per this StackOverflow post. Eventually, it'll be under wakelock_plus/lib/assets/no_sleep.js. The reason being is that it should be moved there so that it's in line with how every other library exposes assets to its users.

You'll also have to modify the existing asset entry in pubspec.yaml so that it points to packages/assets/wakelock_plus/assets/no_sleep.js.

@diegotori
Copy link
Collaborator

@holzgeist Please let me know if you're still gonna work on this change. Otherwise, I can commandeer it for you and take it to the finish line. Thanks.

@holzgeist
Copy link
Author

Hi @diegotori ,

thanks for the feedback. I'm going to work on it, probably today, maybe tomorrow

@holzgeist
Copy link
Author

@diegotori actually I need to solve some other issues before I have a working web-build to test this one. If you could commandeer this, it would be great, thanks 🙏

@diegotori
Copy link
Collaborator

@holzgeist please verify the fixes made to this PR. I was able to do a bit of cleanup and/or fixes. Thanks.

…hat it awaits asynchronous calls from the various wakelock related callbacks. As a result, the Dart layer no longer needs to manually await before calling WakelockPlus.enabled.
@diegotori
Copy link
Collaborator

@holzgeist If you have an angle on the latest no_sleep.js changes that I made, which now awaits for the web layer to enable the wakelock before considering it enabled, please feel free to review.

@ditman the above also applies to you as well, if you're able to review the JS changes that I made. Thanks.

Copy link

@ditman ditman left a comment

Choose a reason for hiding this comment

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

I left some comments, but I'm not an actual owner of the plugin, so please, take/ignore as you please from my comments.

Thanks for getting this fix over the finish line, and apologies for the delay in the review, it took me a long while to see this notification!

Comment on lines 70 to 87
if ((element as HTMLScriptElement).src.endsWith(url)) {
if ((element as web.HTMLScriptElement).src.endsWith(url)) {
Copy link

Choose a reason for hiding this comment

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

I know this change is unrelated, but consider adding an id attribute to your script element, that way this method can be simplified to:

return head.querySelector('#$idForScriptElement') != null;

You may need to keep a small map of urls to each of its idForScriptElement String (probably it'll only contain a single element?)

Copy link
Author

Choose a reason for hiding this comment

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

done. I hope the locking part works out as planned. These things are really hard to test. The happy path works though

@@ -6,13 +6,21 @@ import 'package:wakelock_plus/src/wakelock_plus_web_plugin.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import 'package:wakelock_plus_platform_interface/wakelock_plus_platform_interface.dart';

///
/// Run these tests with:
/// flutter run -d chrome test/wakelock_plus_web_plugin_test.dart
Copy link

Choose a reason for hiding this comment

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

This is better than nothing, but super non-standard! If you want to run tests like this, I'd suggest you try to migrate them to flutter drive, like what we did in flutter/packages, for example:

https://github.com/flutter/packages/tree/main/packages/video_player/video_player_web/example <- this "example" actually contains the integration_test and all that jazz. The README.md should have some links to the docs on how to run those.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@ditman we already have those flutter drive tests declared in example/integration_test/wakelock_plus_test.dart. I guess the question is whether these are the tests that should be run instead of the above ones?

Copy link

Choose a reason for hiding this comment

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

Right, we also have some flutter test --platform=chrome tests in flutter/packages.

I'd recommend using either flutter test or flutter drive to run the tests. I'm not even sure what this program would return if the tests failed? (is this usable for CI, for example?)

Copy link
Collaborator

Choose a reason for hiding this comment

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

@ditman Looks like even after porting this test to use flutter drive, it's still complaining about the requesting page not being visible.

@TestOn('browser')
library;

import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:wakelock_plus/src/wakelock_plus_web_plugin.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
// ignore: depend_on_referenced_packages
import 'package:wakelock_plus_platform_interface/wakelock_plus_platform_interface.dart';

///
/// Run these tests with:
///   flutter run -d chrome test/wakelock_plus_web_plugin_test.dart
///
void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  group('$WakelockPlusWebPlugin', () {
    setUpAll(() async {
      WakelockPlusPlatformInterface.instance = WakelockPlusWebPlugin();
    });

    tearDown(() async {
      await WakelockPlus.disable();
    });

    testWidgets('$WakelockPlusWebPlugin set as default instance',
        (tester) async {
      expect(
          WakelockPlusPlatformInterface.instance, isA<WakelockPlusWebPlugin>());
    });

    testWidgets('initially disabled', (tester) async {
      expect(WakelockPlus.enabled, completion(isFalse));
    });

    testWidgets('enable', (tester) async {
      await WakelockPlus.enable();
      expect(WakelockPlus.enabled, completion(isTrue));
    });

    testWidgets('enable more than once', (tester) async {
      await WakelockPlus.enable();
      await WakelockPlus.enable();
      await WakelockPlus.enable();
      expect(WakelockPlus.enabled, completion(isTrue));
    });

    testWidgets('disable', (tester) async {
      await WakelockPlus.enable();
      await WakelockPlus.disable();
      expect(WakelockPlus.enabled, completion(isFalse));
    });

    testWidgets('disable more than once', (tester) async {
      await WakelockPlus.enable();
      await WakelockPlus.disable();
      await WakelockPlus.disable();
      await WakelockPlus.disable();
      expect(WakelockPlus.enabled, completion(isFalse));
    });

    testWidgets('toggle', (tester) async {
      await WakelockPlus.toggle(enable: true);
      expect(WakelockPlus.enabled, completion(isTrue));

      await WakelockPlus.toggle(enable: false);
      expect(WakelockPlus.enabled, completion(isFalse));
    });
  });
}

Run with while in the example folder:

flutter drive -d web-server --web-port 7357 --browser-name chrome --driver test_driver/integration_test.dart --target integration_test/wakelock_plus_web_plugin_test.dart

Copy link
Collaborator

Choose a reason for hiding this comment

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

Bottom line, what I'm looking for is an integration test that runs on a browser, that can also be spun up in a CI context. Not sure which one is the right approach, since the above is not working at all when using chromedriver.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@ditman looks like it's related to this issue when running flutter test --platform=chrome on wakelock_plus_web_plugin_test.dart in the root test folder.

Not sure what can be done if asset support isn't present when running the tests against a browser.

Copy link

Choose a reason for hiding this comment

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

I suspect the problem is that the WakelockPlus calls must happen in the application under test, and not the test code itself.

If you inject a test app that has a button that enables/disables wakelock, and you trigger the button through the test driver, this should work, and assets would be available.

I think the code here is attempting to run Wakelock in the test runner code, not the application under test? :)

Copy link

Choose a reason for hiding this comment

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

(I don't have time to try my solution right now, but I think the migration to an integration test with flutter driver might be inescapable if we want to test app assets)

Copy link
Collaborator

Choose a reason for hiding this comment

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

So what you're saying is that I should instead inject the Example App, get a lock on the button that toggles the wakelock, and then make assertions from there?

Copy link

Choose a reason for hiding this comment

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

Yes, that's what I'm saying... What I'm not sure now is that the assets are going to be available when the example app runs in flutter drive mode, as you're saying (because your test looks all right to me).

As a reference, a few examples of tests that "inject an app and then look at the DOM of the page or something else" to do integration testing:

Neither of those use assets, though.

Here's an example of an integration test that uses assets:

@holzgeist
Copy link
Author

@diegotori thanks for working on this. But unfortunately this grew way outside of my comfort zone wrt flutter/web so I have to pass on reviewing this 🙈

@diegotori
Copy link
Collaborator

I left some comments, but I'm not an actual owner of the plugin, so please, take/ignore as you please from my comments.

Thanks for getting this fix over the finish line, and apologies for the delay in the review, it took me a long while to see this notification!

Thanks for reviewing this. Since you have a better handle on the JS side of things, I'll let you take point on what I should modify. Feel free to call out more things as you see them.

@holzgeist
Copy link
Author

Hi there!
I'm back to actively working on a flutter/web port of our app. Is there anything I can help with on this PR?

@holzgeist
Copy link
Author

ok, thanks to @ditman 's super detailed review and suggestions I actually was able to understand everything that's going on and apply the suggestions (apart from testing). They definitely all look and feel like improvements, thanks again for the through review 🙏

@diegotori @ditman any thoughts?

@diegotori
Copy link
Collaborator

@holzgeist I'll definitely take a look hopefully this week.

Thanks for your contributions thus far.

@diegotori
Copy link
Collaborator

@holzgeist so far, it LGTM. @ditman, any thoughts on his changes?

Copy link

@ditman ditman left a comment

Choose a reason for hiding this comment

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

Never meant to block this code, thanks for all the improvements!

I don't have time to actually run this code, but if users and CI are happy with it, I don't have much more to say! :)

LGTM!

@@ -6,13 +6,21 @@ import 'package:wakelock_plus/src/wakelock_plus_web_plugin.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import 'package:wakelock_plus_platform_interface/wakelock_plus_platform_interface.dart';

///
/// Run these tests with:
/// flutter run -d chrome test/wakelock_plus_web_plugin_test.dart
Copy link

Choose a reason for hiding this comment

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

Right, we also have some flutter test --platform=chrome tests in flutter/packages.

I'd recommend using either flutter test or flutter drive to run the tests. I'm not even sure what this program would return if the tests failed? (is this usable for CI, for example?)

diegotori and others added 2 commits March 26, 2025 17:20
I got an "undefined" error in the catch branch. The only way this
should be possible if registering a listener fails.
@holzgeist
Copy link
Author

I added a commit to prevent _nativeEnabledCompleter from being null in the catch branch. Since then I realized that I had two requests running in parallel which interfered with each other. I'll still leave the commit there because it doesn't hurt :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants