blob: 9f3c35736dd1fbdcb1a13ed1453fd6a575779f19 [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 'dart:async';
import 'package:dartpad/src/worker_client.dart';
import 'package:dartpad_worker/src/worker.dart';
import 'package:test/test.dart';
import 'asset_server/asset_server_client.dart';
export 'package:dartpad_worker/src/shared.dart';
export 'package:test/test.dart' show fail, group, printOnFailure;
export 'checks_ext.dart';
/// Function used by [testDartWorker] and [testDartWorkspace] to create a
/// worker.
///
/// This defaults to a function creating the worker in the same process, this
/// has several benefits:
/// * It works when testing on VM and in browser.
/// * Faster local iteration, as we don't need to recompile the WASM worker,
/// since the entire worker is compiled into the test program.
/// * Stack traces from the worker are better (especially on the VM).
/// * Printed messages from the worker appear in console for easy debugging.
/// * You can attach a debugger to the whole process.
///
/// The downside of not testing the worker in a _Web Worker_ is that:
/// * Our testing won't cover:
/// - IPC communication,
/// - Worker setup, and,
/// - Cross origin request issues.
/// * The entire worker is compiled along side the test code, so the time to
/// compile a test case is non-trivial.
///
/// To mitigate the compilation time issue, all worker tests are imported into
/// `test_worker.dart` which then calls the `main()` functions. To ensure that
/// we also test with the DartPad worker running as a _Web Worker_ the
/// `integration/test_worker_integration.dart` will override [createWorker] and
/// run all the worker tests with the worker running in a _Web Worker_.
Future<WorkerClient> Function(AssetServerClient server, Uri sdkLocation)
createWorker = (_, _) =>
throw StateError('createWorker function must be defined!');
AssetServerClient? _serverClient;
/// Define a test that uses a [WorkerClient].
void testDartWorker(
String description,
Future<void> Function(WorkerClient worker) body,
) {
test(description, () async {
// Create a test server, if one is not already running.
var sc = _serverClient;
if (sc == null || sc.isClosed) {
sc = _serverClient = await AssetServerClient.spawnHybrid(stayAlive: true);
}
final worker = await createWorker(sc, Uri.parse('dart/'));
try {
await body(worker);
} finally {
await worker.dispose();
}
});
}
/// Define a test that uses [Workspace] pre-populated with a `pubspec.yaml` that
/// has no dependencies.
void testDartWorkspace(
String description,
Future<void> Function(Workspace ws) body,
) {
testDartWorker(description, (worker) async {
final ws = await worker.createWorkspace();
await ws.writeFileFromText('pubspec.yaml', '''
name: myapp
environment:
sdk: '>=3.12.0 <4.0.0'
''');
final (:log) = await ws.pub(command: 'get', args: ['--offline']);
printOnFailure(log);
try {
await body(ws);
} finally {
await ws.dispose();
}
});
}
/// Define a test that runs with a fresh [WorkerClient] connected to an
/// in-memory [Worker] using the Flutter SDK.
void testFlutterWorker(
String description,
Future<void> Function(WorkerClient worker) body,
) {
test(description, () async {
// Create a test server, if one is not already running.
var sc = _serverClient;
if (sc == null || sc.isClosed) {
sc = _serverClient = await AssetServerClient.spawnHybrid(stayAlive: true);
}
if (!sc.hasFlutter) {
markTestSkipped(
'Run pkg/dartpad_worker/tool/setup_local_flutter.dart to '
'enable flutter tests',
);
return;
}
final worker = await createWorker(sc, Uri.parse('flutter/'));
try {
await body(worker);
} finally {
await worker.dispose();
}
});
}
/// Define a test that runs with a fresh [Workspace] connected to an
/// in-memory [Worker] using the Flutter SDK.
void testFlutterWorkspace(
String description,
Future<void> Function(Workspace ws) body,
) {
testFlutterWorker(description, (worker) async {
final ws = await worker.createWorkspace();
await ws.writeFileFromText('pubspec.yaml', r'''
name: myapp
environment:
sdk: '>=3.12.0 <4.0.0'
dependencies:
flutter:
sdk: flutter
''');
final (:log) = await ws.pub(command: 'get');
printOnFailure(log);
try {
await body(ws);
} finally {
await ws.dispose();
}
});
}