Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/asset protocol #1232

Merged
merged 11 commits into from Mar 22, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion integration_tests/.gitignore
Expand Up @@ -37,7 +37,6 @@ lib/generated_plugin_registrant.dart
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
macos/DerivedData/


.specs
pubspec.lock
GeneratedPluginRegistrant.swift
1 change: 0 additions & 1 deletion integration_tests/lib/bridge/from_native.dart
Expand Up @@ -147,7 +147,6 @@ typedef Dart_RegisterTestEnvDartMethods = void Function(Pointer<Uint64> methodBy
final Dart_RegisterTestEnvDartMethods _registerTestEnvDartMethods =
KrakenDynamicLibrary.ref.lookup<NativeFunction<Native_RegisterTestEnvDartMethods>>('registerTestEnvDartMethods').asFunction();


void registerDartTestMethodsToCpp() {
Pointer<Uint64> bytes = malloc.allocate<Uint64>(sizeOf<Uint64>() * _dartNativeMethods.length);
Uint64List nativeMethodList = bytes.asTypedList(_dartNativeMethods.length);
Expand Down
143 changes: 48 additions & 95 deletions integration_tests/lib/main.dart
@@ -1,21 +1,22 @@
import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:kraken/css.dart';
import 'package:kraken/bridge.dart';
import 'package:kraken/dom.dart';
import 'package:kraken/foundation.dart';
import 'package:kraken/gesture.dart';
import 'package:kraken/kraken.dart';
import 'package:kraken/module.dart';
import 'package:kraken/widget.dart';
import 'package:ansicolor/ansicolor.dart';
import 'package:path/path.dart' as path;

import 'bridge/from_native.dart';
import 'bridge/to_native.dart';
import 'bridge/test_input.dart';
import 'custom/custom_element.dart';
import 'package:kraken/gesture.dart';
import 'local_http_server.dart';

String? pass = (AnsiPen()..green())('[TEST PASS]');
Expand All @@ -24,34 +25,16 @@ String? err = (AnsiPen()..red())('[TEST FAILED]');
final String __dirname = path.dirname(Platform.script.path);
final String testDirectory = Platform.environment['KRAKEN_TEST_DIR'] ?? __dirname;

const int KRAKEN_NUM = 1;
Map<int, Kraken> krakenMap = Map();

// Test for UriParser.
class IntegrationTestUriParser extends UriParser {
@override
Uri resolve(Uri base, Uri relative) {
if (base.toString().isEmpty
&& relative.path.startsWith('assets/')) {
return Uri.file(relative.path);
} else {
return super.resolve(base, relative);
}
}
}

// By CLI: `KRAKEN_ENABLE_TEST=true flutter run`
void main() async {
// Overrides library name.
KrakenDynamicLibrary.libName = 'libkraken_test';
defineKrakenCustomElements();

// FIXME: This is a workaround for testcase
ParagraphElement.defaultStyle = {
DISPLAY: BLOCK,
};
// FIXME: This is a workaround for testcases.
ParagraphElement.defaultStyle = { DISPLAY: BLOCK };

// Local HTTP server.
// Start local HTTP server.
var httpServer = LocalHttpServer.getInstance();
print('Local HTTP server started at: ${httpServer.getUri()}');

Expand All @@ -63,43 +46,34 @@ void main() async {
// Set render font family AlibabaPuHuiTi to resolve rendering difference.
CSSText.DEFAULT_FONT_FAMILY_FALLBACK = ['AlibabaPuHuiTi'];

File specs = File(path.join(testDirectory, '.specs/core.build.js'));

List<Map<String, String>> allSpecsPayload = [
{
'filename': path.basename(specs.path),
'filepath': specs.path,
'code': specs.readAsStringSync()
}
];
List<Widget> widgets = [];

for (int i = 0; i < KRAKEN_NUM; i ++) {
KrakenJavaScriptChannel javaScriptChannel = KrakenJavaScriptChannel();
javaScriptChannel.onMethodCall = (String method, dynamic arguments) async {
javaScriptChannel.invokeMethod(method, arguments);
return 'method: ' + method;
};

var kraken = krakenMap[i] = Kraken(
viewportWidth: 360,
viewportHeight: 640,
bundle: KrakenBundle.fromContent('console.log("Starting integration tests...")'),
disableViewportWidthAssertion: true,
disableViewportHeightAssertion: true,
javaScriptChannel: javaScriptChannel,
gestureListener: GestureListener(
onDrag: (GestureEvent gestureEvent) {
if (gestureEvent.state == EVENT_STATE_START) {
var event = CustomEvent('nativegesture', CustomEventInit(detail: 'nativegesture'));
krakenMap[i]!.controller!.view.document.documentElement?.dispatchEvent(event);
}
},
),
uriParser: IntegrationTestUriParser(),
);
widgets.add(kraken);
}
final String specTarget = '.specs/core.build.js';
final File spec = File(path.join(testDirectory, specTarget));
KrakenJavaScriptChannel javaScriptChannel = KrakenJavaScriptChannel();
javaScriptChannel.onMethodCall = (String method, dynamic arguments) async {
javaScriptChannel.invokeMethod(method, arguments);
return 'method: ' + method;
};

// This is a virtual location for test program to test [Location] functionality.
final String specUrl = 'assets:///test.js';
late Kraken kraken;

kraken = Kraken(
wssgcg1213 marked this conversation as resolved.
Show resolved Hide resolved
viewportWidth: 360,
viewportHeight: 640,
bundle: KrakenBundle.fromContent('console.log("Starting integration tests...")', url: specUrl),
disableViewportWidthAssertion: true,
disableViewportHeightAssertion: true,
javaScriptChannel: javaScriptChannel,
gestureListener: GestureListener(
onDrag: (GestureEvent gestureEvent) {
if (gestureEvent.state == EVENT_STATE_START) {
var event = CustomEvent('nativegesture', CustomEventInit(detail: 'nativegesture'));
kraken.controller!.view.document.documentElement?.dispatchEvent(event);
}
},
),
);

runZonedGuarded(() {
runApp(MaterialApp(
Expand All @@ -110,7 +84,9 @@ void main() async {
title: Text('Kraken Integration Tests')
),
body: Wrap(
children: widgets,
children: [
kraken,
],
),
),
));
Expand All @@ -122,41 +98,18 @@ void main() async {

WidgetsBinding.instance!.addPostFrameCallback((_) async {
registerDartTestMethodsToCpp();

List<Future<String>> testResults = [];

for (int i = 0; i < widgets.length; i ++) {
int contextId = i;
initTestFramework(contextId);
addJSErrorListener(contextId, (String err) {
print(err);
});

Map<String, String> payload = allSpecsPayload[i];

// Preload load test cases
String filename = payload['filename']!;
String code = payload['code']!;
evaluateTestScripts(contextId, codeInjection + code, url: filename);

testResults.add(executeTest(contextId));
}

List<String> results = await Future.wait(testResults);

int contextId = kraken.controller!.view.contextId;

initTestFramework(contextId);
addJSErrorListener(contextId, print);
// Preload load test cases
String code = spec.readAsStringSync();
evaluateTestScripts(contextId, codeInjection + code, url: specUrl);
String result = await executeTest(contextId);
// Manual dispose context for memory leak check.
krakenMap.forEach((key, kraken) {
disposePage(kraken.controller!.view.contextId);
});

for (int i = 0; i < results.length; i ++) {
String status = results[i];
if (status == 'failed') {
exit(1);
}
}

exit(0);
disposePage(kraken.controller!.view.contextId);

exit(result == 'failed' ? 1 : 0);
});
}

16 changes: 12 additions & 4 deletions kraken/example/assets/bundle.html
@@ -1,18 +1,26 @@
<!doctype html>
<html>
<head>
<style>
.title {
.container {
margin: 64px 0 32px;
text-align: center;
}
.logo {
width: 128px;
}
.p {
color: red;
color: #ff6633;
line-height: 1.7em;
}
</style>
</head>
<body>
<h1 class="title">Rendering in HTML.</h1>
<div class="container">
<img class="logo" src="./kraken.png" />
</div>
<script>
console.log('Hello World!');
console.log('Welcome to Kraken!');
</script>
<script src="./bundle.js" ></script>
</body>
Expand Down
4 changes: 2 additions & 2 deletions kraken/example/assets/bundle.js
@@ -1,6 +1,6 @@
var text1 = document.createTextNode('Hello World!');
var text1 = document.createTextNode('Hello Kraken!');
var br = document.createElement('br');
var text2 = document.createTextNode('你好,世界!');
var text2 = document.createTextNode('你好,北海!');
var p = document.createElement('p');
p.className = 'p';
p.style.textAlign = 'center';
Expand Down
Binary file added kraken/example/assets/kraken.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion kraken/example/lib/main.dart
Expand Up @@ -93,7 +93,7 @@ class _MyHomePageState extends State<MyBrowser> {
devToolsService: ChromeDevToolsService(),
viewportWidth: viewportSize.width - queryData.padding.horizontal,
viewportHeight: viewportSize.height - appBar.preferredSize.height - queryData.padding.vertical,
bundle: KrakenBundle.fromUrl('assets://assets/bundle.js'),
bundle: KrakenBundle.fromUrl('assets:///assets/bundle.html'),
),
));
}
Expand Down
29 changes: 18 additions & 11 deletions kraken/lib/src/launcher/bundle.dart
Expand Up @@ -16,14 +16,12 @@ import 'package:kraken/launcher.dart';
import 'package:kraken/module.dart';
import 'package:kraken/css.dart';

import 'manifest.dart';

const String BUNDLE_URL = 'KRAKEN_BUNDLE_URL';
const String BUNDLE_PATH = 'KRAKEN_BUNDLE_PATH';
const String ENABLE_DEBUG = 'KRAKEN_ENABLE_DEBUG';
const String ENABLE_PERFORMANCE_OVERLAY = 'KRAKEN_ENABLE_PERFORMANCE_OVERLAY';

const String ASSETS_PROROCOL = 'assets://';
const String ASSETS_PROTOCOL = 'assets://';
final ContentType css = ContentType('text', 'css', charset: 'utf-8');

String? getBundleURLFromEnv() {
Expand All @@ -50,7 +48,7 @@ String getAcceptHeader() {
}

bool isAssetAbsolutePath(String path) {
return path.startsWith(ASSETS_PROROCOL);
return path.startsWith(ASSETS_PROTOCOL);
}

abstract class KrakenBundle {
Expand All @@ -69,8 +67,6 @@ abstract class KrakenBundle {
String? content;
// JS line offset, default to 0.
int lineOffset = 0;
// Kraken bundle manifest
AppManifest? manifest;

bool isResolved = false;

Expand Down Expand Up @@ -275,12 +271,23 @@ class AssetsBundle extends KrakenBundle {
@override
Future<KrakenBundle> resolve(int? contextId) async {
super.resolve(contextId);
// JSBundle get default bundle manifest.
manifest = AppManifest();
if (isAssetAbsolutePath(src)) {
String localPath = src.substring(ASSETS_PROROCOL.length);
rawBundle = await rootBundle.load(localPath);
final Uri? _resolvedUri = resolvedUri;
if (_resolvedUri != null) {
final String assetName = getAssetName(_resolvedUri);
rawBundle = await rootBundle.load(assetName);
}
return this;
}

/// Get flutter asset name from uri scheme asset.
/// eg: assets://foo/bar.html -> foo/bar.html
wssgcg1213 marked this conversation as resolved.
Show resolved Hide resolved
static String getAssetName(Uri resolvedUri) {
String assetName = resolvedUri.path;
wssgcg1213 marked this conversation as resolved.
Show resolved Hide resolved

// Remove leading `/`
if (assetName.startsWith('/')) {
assetName = assetName.substring(1);
}
return assetName;
}
}