Report original test location in the json_reporter if different (#853)
* add root_line, root_column, and root_package_url to the json reporter
* update docs, pubspec, changelog
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6623494..2548d8d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.12.40
+
+* Added some new optional fields to the json reporter, `root_line`,
+ `root_column`, and `root_url`. These will be present if `url` is not the same
+ as the suite url, and will represent the location in the original test suite
+ from which the call to `test` originated.
+
## 0.12.39
* Change the default reporter and color defaults to be based on
diff --git a/doc/json_reporter.md b/doc/json_reporter.md
index 9c54fe7..a5a461a 100644
--- a/doc/json_reporter.md
+++ b/doc/json_reporter.md
@@ -343,6 +343,23 @@
// The URL for the file in which the test was defined, or `null`.
String url;
+ // The (1-based) line in the original test suite from which the test
+ // originated.
+ //
+ // Will only be present if `root_url` is different from `url`.
+ int root_line;
+
+ // The (1-based) line on in the original test suite from which the test
+ // originated.
+ //
+ // Will only be present if `root_url` is different from `url`.
+ int root_column;
+
+ // The URL for the original test suite in which the test was defined.
+ //
+ // Will only be present if different from `url`.
+ String root_url;
+
// This field is deprecated and should not be used.
Metadata metadata;
}
diff --git a/lib/src/runner/reporter/json.dart b/lib/src/runner/reporter/json.dart
index ec27478..4c0f160 100644
--- a/lib/src/runner/reporter/json.dart
+++ b/lib/src/runner/reporter/json.dart
@@ -5,6 +5,8 @@
import 'dart:async';
import 'dart:convert';
+import 'package:path/path.dart' as p;
+
import '../../backend/group.dart';
import '../../backend/group_entry.dart';
import '../../backend/live_test.dart';
@@ -131,7 +133,8 @@
"metadata": _serializeMetadata(suiteConfig, liveTest.test.metadata)
},
liveTest.test,
- liveTest.suite.platform.runtime)
+ liveTest.suite.platform.runtime,
+ liveTest.suite.path)
});
/// Convert the future to a stream so that the subscription can be paused or
@@ -218,7 +221,8 @@
"testCount": group.testCount
},
group,
- suite.platform.runtime)
+ suite.platform.runtime,
+ suite.path)
});
parentID = id;
return id;
@@ -280,17 +284,32 @@
}
/// Modifies [map] to include line, column, and URL information from the first
- /// frame of [entry.trace].
+ /// frame of [entry.trace], as well as the first line in the original file.
///
/// Returns [map].
- Map<String, dynamic> _addFrameInfo(SuiteConfiguration suiteConfig,
- Map<String, dynamic> map, GroupEntry entry, Runtime runtime) {
+ Map<String, dynamic> _addFrameInfo(
+ SuiteConfiguration suiteConfig,
+ Map<String, dynamic> map,
+ GroupEntry entry,
+ Runtime runtime,
+ String suitePath) {
var frame = entry.trace?.frames?.first;
- if (suiteConfig.jsTrace && runtime.isJS) frame = null;
+ var rootFrame = entry.trace?.frames?.firstWhere(
+ (frame) => frame.uri.path == p.absolute(suitePath),
+ orElse: () => null);
+ if (suiteConfig.jsTrace && runtime.isJS) {
+ frame = null;
+ rootFrame = null;
+ }
map["line"] = frame?.line;
map["column"] = frame?.column;
map["url"] = frame?.uri?.toString();
+ if (rootFrame != null && rootFrame != frame) {
+ map["root_line"] = rootFrame.line;
+ map["root_column"] = rootFrame.column;
+ map["root_url"] = rootFrame.uri.toString();
+ }
return map;
}
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 5719dbe..7068ad3 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: test
-version: 0.12.39
+version: 0.12.40
author: Dart Team <misc@dartlang.org>
description: A library for writing dart unit tests.
homepage: https://github.com/dart-lang/test
diff --git a/test/common.dart b/test/common.dart
new file mode 100644
index 0000000..cde6147
--- /dev/null
+++ b/test/common.dart
@@ -0,0 +1,3 @@
+import 'package:test/test.dart';
+
+myTest(String name, Function testFn) => test(name, testFn);
diff --git a/test/runner/json_reporter_test.dart b/test/runner/json_reporter_test.dart
index 2dab958..2127357 100644
--- a/test/runner/json_reporter_test.dart
+++ b/test/runner/json_reporter_test.dart
@@ -492,6 +492,37 @@
"chrome"
]);
}, tags: ["chrome"], skip: "Broken by sdk#29693.");
+
+ test("the root suite if applicable", () {
+ return _expectReport("""
+ customTest('success 1', () {});
+ test('success 2', () {});
+ """, [
+ _start,
+ _allSuites(),
+ _suite(0),
+ _testStart(1, "loading test.dart", groupIDs: []),
+ _testDone(1, hidden: true),
+ _group(2, testCount: 2),
+ _testStart(3, "success 1",
+ line: 3,
+ column: 50,
+ url: p.toUri(p.join(d.sandbox, "common.dart")).toString(),
+ root_column: 7,
+ root_line: 7,
+ root_url: p.toUri(p.join(d.sandbox, "test.dart")).toString()),
+ _testDone(3),
+ _testStart(4, "success 2", line: 8, column: 7),
+ _testDone(4),
+ _done()
+ ], externalLibraries: {
+ 'common.dart': """
+import 'package:test/test.dart';
+
+void customTest(String name, Function testFn) => test(name, testFn);
+""",
+ });
+ });
});
test(
@@ -519,19 +550,29 @@
/// Asserts that the tests defined by [tests] produce the JSON events in
/// [expected].
+///
+/// If [externalLibraries] are provided it should be a map of relative file
+/// paths to contents. All libraries will be added as imports to the test, and
+/// files will be created for them.
Future _expectReport(String tests, List<Map> expected,
- {List<String> args}) async {
- d.file("test.dart", """
- import 'dart:async';
+ {List<String> args, Map<String, String> externalLibraries}) async {
+ args ??= [];
+ externalLibraries ??= {};
+ var testContent = new StringBuffer("""
+import 'dart:async';
- import 'package:test/test.dart';
+import 'package:test/test.dart';
- void main() {
-$tests
- }
- """).create();
+""");
+ for (var entry in externalLibraries.entries) {
+ testContent.writeln("import '${entry.key}';");
+ await d.file(entry.key, entry.value).create();
+ }
+ testContent..writeln("void main() {")..writeln(tests)..writeln("}");
- var test = await runTest(["test.dart"]..addAll(args ?? []), reporter: "json");
+ await d.file("test.dart", testContent.toString()).create();
+
+ var test = await runTest(["test.dart"]..addAll(args), reporter: "json");
await test.shouldExit();
var stdoutLines = await test.stdoutStream().toList();
@@ -622,13 +663,23 @@
/// reason. If it's a [String], the test is expected to be marked as skipped
/// with that reason.
Map _testStart(int id, String name,
- {int suiteID, Iterable<int> groupIDs, int line, int column, skip}) {
+ {int suiteID,
+ Iterable<int> groupIDs,
+ int line,
+ int column,
+ String url,
+ skip,
+ int root_line,
+ int root_column,
+ String root_url}) {
if ((line == null) != (column == null)) {
throw new ArgumentError(
"line and column must either both be null or both be passed");
}
- return {
+ url ??=
+ line == null ? null : p.toUri(p.join(d.sandbox, "test.dart")).toString();
+ var expected = {
"type": "testStart",
"test": {
"id": id,
@@ -638,11 +689,20 @@
"metadata": _metadata(skip: skip),
"line": line,
"column": column,
- "url": line == null
- ? null
- : p.toUri(p.join(d.sandbox, "test.dart")).toString()
+ "url": url,
}
};
+ var testObj = expected['test'] as Map<String, dynamic>;
+ if (root_line != null) {
+ testObj['root_line'] = root_line;
+ }
+ if (root_column != null) {
+ testObj['root_column'] = root_column;
+ }
+ if (root_url != null) {
+ testObj['root_url'] = root_url;
+ }
+ return expected;
}
/// Returns the event emitted by the JSON reporter indicating that a test