drift/extras/integration_tests/web_wasm/lib/driver.dart

167 lines
5.0 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'dart:isolate';
import 'package:build_daemon/client.dart';
import 'package:build_daemon/constants.dart';
import 'package:build_daemon/data/build_status.dart';
import 'package:build_daemon/data/build_target.dart';
import 'package:collection/collection.dart';
import 'package:package_config/package_config.dart';
import 'package:path/path.dart' as p;
import 'package:shelf/shelf_io.dart';
import 'package:shelf_proxy/shelf_proxy.dart';
import 'package:web_wasm/initialization_mode.dart';
import 'package:webdriver/async_io.dart';
// ignore: implementation_imports
import 'package:drift/src/web/wasm_setup/types.dart';
class TestAssetServer {
final BuildDaemonClient buildRunner;
late final HttpServer server;
TestAssetServer(this.buildRunner);
Future<void> close() async {
await server.close(force: true);
await buildRunner.close();
}
static Future<TestAssetServer> start() async {
final packageConfig =
await loadPackageConfigUri((await Isolate.packageConfig)!);
final ownPackage = packageConfig['web_wasm']!.root;
var packageDir = ownPackage.toFilePath(windows: Platform.isWindows);
if (packageDir.endsWith('/')) {
packageDir = packageDir.substring(0, packageDir.length - 1);
}
final buildRunner = await BuildDaemonClient.connect(
packageDir,
[
Platform.executable, // dart
'run',
'build_runner',
'daemon',
],
logHandler: (log) => print(log.message),
);
buildRunner
..registerBuildTarget(DefaultBuildTarget((b) => b.target = 'web'))
..startBuild();
// Wait for the build to complete, so that the server we return is ready to
// go.
await buildRunner.buildResults.firstWhere((b) {
final buildResult = b.results.firstWhereOrNull((r) => r.target == 'web');
return buildResult != null && buildResult.status != BuildStatus.started;
});
final assetServerPortFile =
File(p.join(daemonWorkspace(packageDir), '.asset_server_port'));
final assetServerPort = int.parse(await assetServerPortFile.readAsString());
final server = TestAssetServer(buildRunner);
final proxy = proxyHandler('http://localhost:$assetServerPort/web/');
server.server = await serve(
(request) async {
final pathSegments = request.url.pathSegments;
if (pathSegments.isNotEmpty && pathSegments[0] == 'no-coep') {
// Serve stuff under /no-coep like the regular website, but without
// adding the security headers.
return await proxy(request.change(path: 'no-coep'));
} else {
final response = await proxy(request);
if (!request.url.path.startsWith('/no-coep')) {
return response.change(headers: {
// Needed for shared array buffers to work
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp'
});
}
return response;
}
},
'localhost',
8080,
);
return server;
}
}
class DriftWebDriver {
final TestAssetServer server;
final WebDriver driver;
DriftWebDriver(this.server, this.driver);
Future<
({
Set<WasmStorageImplementation> storages,
Set<MissingBrowserFeature> missingFeatures,
List<ExistingDatabase> existing,
})> probeImplementations() async {
final rawResult = await driver
.executeAsync('detectImplementations("", arguments[0])', []);
final result = json.decode(rawResult);
return (
storages: {
for (final entry in result['impls'])
WasmStorageImplementation.values.byName(entry)
},
missingFeatures: {
for (final entry in result['missing'])
MissingBrowserFeature.values.byName(entry)
},
existing: <ExistingDatabase>[
for (final entry in result['existing'])
(
WebStorageApi.byName[entry[0] as String]!,
entry[1] as String,
),
],
);
}
Future<void> openDatabase([WasmStorageImplementation? implementation]) async {
await driver.executeAsync(
'open(arguments[0], arguments[1])', [implementation?.name]);
}
Future<void> insertIntoDatabase() async {
await driver.executeAsync('insert("", arguments[0])', []);
}
Future<int> get amountOfRows async {
return await driver.executeAsync('get_rows("", arguments[0])', []);
}
Future<void> waitForTableUpdate() async {
await driver.executeAsync('wait_for_update("", arguments[0])', []);
}
Future<void> enableInitialization(InitializationMode mode) async {
final result = await driver.executeAsync(
'enable_initialization(arguments[0], arguments[1])',
[mode.name],
);
if (result != true) {
throw 'Could not set initialization mode';
}
}
Future<void> deleteDatabase(WebStorageApi storageApi, String name) async {
await driver.executeAsync('delete_database(arguments[0], arguments[1])', [
json.encode([storageApi.name, name]),
]);
}
}