Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions dwds/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
## 16.0.2-dev

- Include debug information in the event sent from the injected client to the
Dart Debug Extension notifying that the Dart app is ready.
- Include an optional param to `Dwds.start` to indicate whether it is running
internally or externally.

## 16.0.1

- Allow the following API to return `null` and add error handling:
- `LoadStrategy.serverPathForModule`
- `LoadStrategy.sourceMapPathForModule`
- Expression evaluation performance improvement:
- Batch `ChromeProxyService.evaluate()` requests that are close in time
and are executed in the same library and scope.
- Update `package:file` version to `6.13` or greater to handle https://github.com/dart-lang/sdk/issues/49647.
- Batch `ChromeProxyService.evaluate()` requests that are close in time and
are executed in the same library and scope.
- Update `package:file` version to `6.13` or greater to handle
https://github.com/dart-lang/sdk/issues/49647.

## 16.0.0

Expand Down
6 changes: 6 additions & 0 deletions dwds/debug_extension_mv3/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ dev_dependencies:
build: ^2.0.0
build_web_compilers: ^3.0.0
build_runner: ^2.0.6
dwds: ^16.0.0

dependency_overrides:
dwds:
path: ..

24 changes: 21 additions & 3 deletions dwds/debug_extension_mv3/web/background.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
@JS()
library background;

import 'dart:html';

import 'package:dwds/data/debug_info.dart';
import 'package:js/js.dart';

import 'chrome_api.dart';
import 'messaging.dart';
import 'web_api.dart';

void main() {
_registerListeners();
Expand All @@ -22,13 +26,27 @@ void _handleRuntimeMessages(
dynamic jsRequest, MessageSender sender, Function sendResponse) async {
if (jsRequest is! String) return;

interceptMessage(
interceptMessage<DebugInfo>(
message: jsRequest,
expectedType: MessageType.debugInfo,
expectedSender: Script.detector,
expectedRecipient: Script.background,
expectedType: MessageType.dartAppReady,
messageHandler: (_) {
messageHandler: (DebugInfo debugInfo) async {
final currentTab = await _getTab();
final currentUrl = currentTab?.url ?? '';
final appUrl = debugInfo.appUrl ?? '';
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to add tests to make sure all the data in the debug info is received here?

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 can't think of a good way to test this until we are actually using the debug info to trigger a debug session. We don't have access to the extension icon to see if it has been changed (that is why we have this onFakeClick method in the MV2 extension, and we can't intercept runtime messages in tests because they are for extension communication only.

Once more of the functionality is added (and we are triggering a debug session) the existence of these values can be tested.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh but I can add tests for the injected client until then, will update those!

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 was able to add a test for the internal build property on the window object. Not sure how to test the CustomEvent unfortunately. Ideally webdriver would have a way of registering an event listener on the page document, so that we could load up the dart app and listen for the dart-app-ready event and confirm that the properties are what we expect, but unfortunately webdriver doesn't support event listeners like that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks Elliott! We chatter offline about adding test in subsequent PRs.

if (currentUrl.isEmpty || appUrl.isEmpty || currentUrl != appUrl) {
console.warn(
'Dart app detected at $appUrl but current tab is $currentUrl.');
return;
}
// Update the icon to show that a Dart app has been detected:
chrome.action.setIcon(IconInfo(path: 'dart.png'), /*callback*/ null);
});
}

Future<Tab?> _getTab() async {
final query = QueryInfo(active: true, currentWindow: true);
final tabs = List<Tab>.from(await promiseToFuture(chrome.tabs.query(query)));
return tabs.isNotEmpty ? tabs.first : null;
}
19 changes: 19 additions & 0 deletions dwds/debug_extension_mv3/web/chrome_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ external Chrome get chrome;
class Chrome {
external Action get action;
external Runtime get runtime;
external Tabs get tabs;
}

/// chrome.action APIs
Expand Down Expand Up @@ -66,6 +67,24 @@ class MessageSender {
external factory MessageSender({String? id, String? url, Tab? tab});
}

/// chrome.tabs APIs
/// https://developer.chrome.com/docs/extensions/reference/tabs

@JS()
@anonymous
class Tabs {
external Object query(QueryInfo queryInfo);
}

@JS()
@anonymous
class QueryInfo {
external bool get active;
external bool get currentWindow;
external String get url;
external factory QueryInfo({bool? active, bool? currentWindow, String? url});
}

@JS()
@anonymous
class Tab {
Expand Down
11 changes: 9 additions & 2 deletions dwds/debug_extension_mv3/web/detector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
library detector;

import 'dart:html';
import 'dart:js_util';
import 'package:js/js.dart';

import 'chrome_api.dart';
import 'messaging.dart';
import 'web_api.dart';

void main() {
_registerListeners();
Expand All @@ -20,9 +22,14 @@ void _registerListeners() {
}

void _onDartAppReadyEvent(Event event) {
final debugInfo = getProperty(event, 'detail') as String?;
if (debugInfo == null) {
console.warn('Can\'t debug Dart app without debug info.');
return;
}
_sendMessageToBackgroundScript(
type: MessageType.dartAppReady,
body: 'Dart app ready!',
type: MessageType.debugInfo,
body: debugInfo,
);
}

Expand Down
19 changes: 10 additions & 9 deletions dwds/debug_extension_mv3/web/messaging.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ library messaging;

import 'dart:convert';

import 'package:dwds/data/serializers.dart';
import 'package:js/js.dart';

import 'web_api.dart';
Expand All @@ -21,7 +22,7 @@ enum Script {
}

enum MessageType {
dartAppReady;
debugInfo;

factory MessageType.fromString(String value) {
return MessageType.values.byName(value);
Expand Down Expand Up @@ -57,34 +58,34 @@ class Message {

String toJSON() {
return jsonEncode({
'type': type.name,
'to': to.name,
'from': from.name,
'encodedBody': body,
'type': type.name,
'body': body,
if (error != null) 'error': error,
});
}
}

void interceptMessage({
void interceptMessage<T>({
required String? message,
required MessageType expectedType,
required Script expectedSender,
required Script expectedRecipient,
required void Function(String message) messageHandler,
required void Function(T message) messageHandler,
}) {
if (message == null) return;
try {
if (message == null) return;
final decodedMessage = Message.fromJSON(message);
if (decodedMessage.type != expectedType ||
decodedMessage.to != expectedRecipient ||
decodedMessage.from != expectedSender) {
return;
}
messageHandler(decodedMessage.body);
messageHandler(
serializers.deserialize(jsonDecode(decodedMessage.body)) as T);
} catch (error) {
console.warn(
'Error intercepting $expectedType message from $expectedSender to $expectedRecipient: $error');
return;
'Error intercepting $expectedType from $expectedSender to $expectedRecipient: $error');
}
}
1 change: 1 addition & 0 deletions dwds/lib/dart_web_debug_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class Dwds {
bool launchDevToolsInNewWindow = true,
SdkConfigurationProvider? sdkConfigurationProvider,
bool emitDebugEvents = true,
bool isInternalBuild = false,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is something passing this value, or is is it going to be added in future CLs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not yet, this will get passed by flutter_tools, ddr etc when they start dwds

}) async {
globalLoadStrategy = loadStrategy;
sdkConfigurationProvider ??= DefaultSdkConfigurationProvider();
Expand Down
16 changes: 16 additions & 0 deletions dwds/lib/data/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# How to generate data files:

## Creating a new data file:

1. Create a new file for your data type in the `/data` directory with the
`.dart` extension
1. Create an abstract class for your data type (see existing files for examples)
1. Add the new data type to `/data/serializers.dart` 4 Run:
`dart run build_runner build` from DWDS root (this will generate the
`.g.dart` file)

## To update an existing data file:

1. Make your changes
1. Run: `dart run build_runner clean` from DWDS root
1. Run: `dart run build_runner build` from DWDS root
25 changes: 25 additions & 0 deletions dwds/lib/data/debug_info.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';

part 'debug_info.g.dart';

abstract class DebugInfo implements Built<DebugInfo, DebugInfoBuilder> {
static Serializer<DebugInfo> get serializer => _$debugInfoSerializer;

factory DebugInfo([Function(DebugInfoBuilder) updates]) = _$DebugInfo;

DebugInfo._();

String? get appEntrypointPath;
String? get appId;
String? get appInstanceId;
String? get appOrigin;
String? get appUrl;
String? get dwdsVersion;
String? get extensionUrl;
bool? get isInternalBuild;
}
Loading