blob: 40732413d6571bbad3b2cfd66151fc0e5eb9b7fe [file] [edit]
// Copyright (c) 2026, 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:checks/context.dart';
import 'package:dartpad/dartpad.dart';
import 'package:test/test.dart';
import 'package:web/web.dart' as web;
import 'asset_server/asset_server_client.dart';
export 'package:test/test.dart' show TestOn, printOnFailure;
export 'checks_ext.dart';
final class TestContext {
final AssetServerClient server;
final DartPad dartpad;
final Workspace ws;
final Sandbox sandbox;
final consoleLog = <String>[];
TestContext._(this.server, this.dartpad, this.ws, this.sandbox) {
sandbox.onConsole.listen((event) {
consoleLog.add(event.message);
printOnFailure('[sandbox] console.${event.level.name}: ${event.message}');
});
}
/// Check that console has emitted or will emit a message satisfying
/// [condition].
Future<void> checkConsole(
Condition<String> condition, {
Duration timeLimit = const Duration(seconds: 5),
}) async {
if (consoleLog.any((line) => softCheck(line, condition) == null)) {
return;
}
await sandbox.onConsole
.firstWhere((event) => softCheck(event.message, condition) == null)
.timeout(
timeLimit,
onTimeout: () => throw TestFailure(
'Expected console message with $timeLimit that '
'${describe(condition).join('\n')}',
),
);
}
}
void testDartIntegration(
String description,
Future<void> Function(TestContext ctx) fn,
) {
test(description, () async {
final server = await AssetServerClient.spawnHybrid(stayAlive: false);
// Initialize DartPad Worker
printOnFailure('# Creating worker');
final dartpad = await DartPad.create(
assetBaseUrl: server.assetUrl,
sdkLocation: Uri.parse('dart/'),
pubHostedUrl: server.baseUrl,
);
printOnFailure('# Creating workspace');
final workspace = await dartpad.createWorkspace();
// Initialize Sandbox
printOnFailure('# Initializing sandbox');
final sandbox = await Sandbox.createIFrame(
web.document.body!,
assetBaseUrl: server.assetUrl,
sdkLocation: server.assetUrl.resolve('dart/'),
);
try {
await fn(TestContext._(server, dartpad, workspace, sandbox));
} finally {
try {
sandbox.dispose();
} finally {
try {
await workspace.dispose();
} finally {
await dartpad.dispose();
}
}
}
});
}
void testFlutterIntegration(
String description,
Future<void> Function(TestContext ctx) fn,
) {
test(description, timeout: const Timeout(Duration(seconds: 120)), () async {
final server = await AssetServerClient.spawnHybrid(stayAlive: false);
if (!server.hasFlutter) {
markTestSkipped(
'Run pkg/dartpad_worker/tool/setup_local_flutter.dart to '
'enable flutter tests',
);
return;
}
// Initialize DartPad Worker
printOnFailure('# Creating worker');
final dartpad = await DartPad.create(
assetBaseUrl: server.assetUrl,
sdkLocation: Uri.parse('flutter/'),
pubHostedUrl: server.baseUrl,
);
printOnFailure('# Creating workspace');
final workspace = await dartpad.createWorkspace();
// Initialize Sandbox
printOnFailure('# Initializing sandbox');
final sandbox = await Sandbox.createIFrame(
web.document.body!,
assetBaseUrl: server.assetUrl,
sdkLocation: server.assetUrl.resolve('flutter/'),
);
try {
await fn(TestContext._(server, dartpad, workspace, sandbox));
} finally {
try {
sandbox.dispose();
} finally {
try {
await workspace.dispose();
} finally {
await dartpad.dispose();
}
}
}
});
}