Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
4832e64c
Unverified
Commit
4832e64c
authored
Nov 19, 2020
by
Jonah Williams
Committed by
GitHub
Nov 19, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tools] remove globals from flutter web platform (#70863)
parent
085ff127
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
306 additions
and
280 deletions
+306
-280
flutter_web_goldens.dart
packages/flutter_tools/lib/src/test/flutter_web_goldens.dart
+195
-0
flutter_web_platform.dart
...ages/flutter_tools/lib/src/test/flutter_web_platform.dart
+95
-278
runner.dart
packages/flutter_tools/lib/src/test/runner.dart
+14
-0
golden_comparator_process_test.dart
...est/general.shard/web/golden_comparator_process_test.dart
+1
-1
golden_comparator_test.dart
..._tools/test/general.shard/web/golden_comparator_test.dart
+1
-1
No files found.
packages/flutter_tools/lib/src/test/flutter_web_goldens.dart
0 → 100644
View file @
4832e64c
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: implementation_imports
import
'dart:async'
;
import
'dart:typed_data'
;
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../convert.dart'
;
import
'../globals.dart'
as
globals
;
import
'test_compiler.dart'
;
import
'test_config.dart'
;
/// Helper class to start golden file comparison in a separate process.
///
/// Golden file comparator is configured using flutter_test_config.dart and that
/// file can contain arbitrary Dart code that depends on dart:ui. Thus it has to
/// be executed in a `flutter_tester` environment. This helper class generates a
/// Dart file configured with flutter_test_config.dart to perform the comparison
/// of golden files.
class
TestGoldenComparator
{
/// Creates a [TestGoldenComparator] instance.
TestGoldenComparator
(
this
.
shellPath
,
this
.
compilerFactory
)
:
tempDir
=
globals
.
fs
.
systemTempDirectory
.
createTempSync
(
'flutter_web_platform.'
);
final
String
shellPath
;
final
Directory
tempDir
;
final
TestCompiler
Function
()
compilerFactory
;
TestCompiler
_compiler
;
TestGoldenComparatorProcess
_previousComparator
;
Uri
_previousTestUri
;
Future
<
void
>
close
()
async
{
tempDir
.
deleteSync
(
recursive:
true
);
await
_compiler
?.
dispose
();
await
_previousComparator
?.
close
();
}
/// Start golden comparator in a separate process. Start one file per test file
/// to reduce the overhead of starting `flutter_tester`.
Future
<
TestGoldenComparatorProcess
>
_processForTestFile
(
Uri
testUri
)
async
{
if
(
testUri
==
_previousTestUri
)
{
return
_previousComparator
;
}
final
String
bootstrap
=
TestGoldenComparatorProcess
.
generateBootstrap
(
testUri
);
final
Process
process
=
await
_startProcess
(
bootstrap
);
unawaited
(
_previousComparator
?.
close
());
_previousComparator
=
TestGoldenComparatorProcess
(
process
);
_previousTestUri
=
testUri
;
return
_previousComparator
;
}
Future
<
Process
>
_startProcess
(
String
testBootstrap
)
async
{
// Prepare the Dart file that will talk to us and start the test.
final
File
listenerFile
=
(
await
tempDir
.
createTemp
(
'listener'
)).
childFile
(
'listener.dart'
);
await
listenerFile
.
writeAsString
(
testBootstrap
);
// Lazily create the compiler
_compiler
=
_compiler
??
compilerFactory
();
final
String
output
=
await
_compiler
.
compile
(
listenerFile
.
uri
);
final
List
<
String
>
command
=
<
String
>[
shellPath
,
'--disable-observatory'
,
'--non-interactive'
,
'--packages=
${globals.fs.path.join('.dart_tool', 'package_config.json')}
'
,
output
,
];
final
Map
<
String
,
String
>
environment
=
<
String
,
String
>{
// Chrome is the only supported browser currently.
'FLUTTER_TEST_BROWSER'
:
'chrome'
,
};
return
globals
.
processManager
.
start
(
command
,
environment:
environment
);
}
Future
<
String
>
compareGoldens
(
Uri
testUri
,
Uint8List
bytes
,
Uri
goldenKey
,
bool
updateGoldens
)
async
{
final
File
imageFile
=
await
(
await
tempDir
.
createTemp
(
'image'
)).
childFile
(
'image'
).
writeAsBytes
(
bytes
);
final
TestGoldenComparatorProcess
process
=
await
_processForTestFile
(
testUri
);
process
.
sendCommand
(
imageFile
,
goldenKey
,
updateGoldens
);
final
Map
<
String
,
dynamic
>
result
=
await
process
.
getResponse
();
if
(
result
==
null
)
{
return
'unknown error'
;
}
else
{
return
(
result
[
'success'
]
as
bool
)
?
null
:
((
result
[
'message'
]
as
String
)
??
'does not match'
);
}
}
}
/// Represents a `flutter_tester` process started for golden comparison. Also
/// handles communication with the child process.
class
TestGoldenComparatorProcess
{
/// Creates a [TestGoldenComparatorProcess] backed by [process].
TestGoldenComparatorProcess
(
this
.
process
)
{
// Pipe stdout and stderr to printTrace and printError.
// Also parse stdout as a stream of JSON objects.
streamIterator
=
StreamIterator
<
Map
<
String
,
dynamic
>>(
process
.
stdout
.
transform
<
String
>(
utf8
.
decoder
)
.
transform
<
String
>(
const
LineSplitter
())
.
where
((
String
line
)
{
globals
.
printTrace
(
'<<<
$line
'
);
return
line
.
isNotEmpty
&&
line
[
0
]
==
'{'
;
})
.
map
<
dynamic
>(
jsonDecode
)
.
cast
<
Map
<
String
,
dynamic
>>());
process
.
stderr
.
transform
<
String
>(
utf8
.
decoder
)
.
transform
<
String
>(
const
LineSplitter
())
.
forEach
((
String
line
)
{
globals
.
printError
(
'<<<
$line
'
);
});
}
final
Process
process
;
StreamIterator
<
Map
<
String
,
dynamic
>>
streamIterator
;
Future
<
void
>
close
()
async
{
await
process
.
stdin
.
close
();
process
.
kill
();
}
void
sendCommand
(
File
imageFile
,
Uri
goldenKey
,
bool
updateGoldens
)
{
final
Object
command
=
jsonEncode
(<
String
,
dynamic
>{
'imageFile'
:
imageFile
.
path
,
'key'
:
goldenKey
.
toString
(),
'update'
:
updateGoldens
,
});
globals
.
printTrace
(
'Preparing to send command:
$command
'
);
process
.
stdin
.
writeln
(
command
);
}
Future
<
Map
<
String
,
dynamic
>>
getResponse
()
async
{
final
bool
available
=
await
streamIterator
.
moveNext
();
assert
(
available
);
return
streamIterator
.
current
;
}
static
String
generateBootstrap
(
Uri
testUri
)
{
final
File
testConfigFile
=
findTestConfigFile
(
globals
.
fs
.
file
(
testUri
));
// Generate comparator process for the file.
return
'''
// @dart=2.9
import '
dart:
convert
'; // ignore: dart_convert_import
import '
dart:
io
'; // ignore: dart_io_import
import '
package:
flutter_test
/
flutter_test
.
dart
';
${testConfigFile != null ? "import '${Uri.file(testConfigFile.path)}
'
as
test_config
;
" : ""}
void main() async {
LocalFileComparator comparator = LocalFileComparator(Uri.parse('
$testUri
'));
goldenFileComparator = comparator;
${testConfigFile != null ? 'test_config.testExecutable(() async {' : ''}
final commands = stdin
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
.map<Object>(jsonDecode);
await for (final Object command in commands) {
if (command is Map<String, dynamic>) {
File imageFile = File(command['imageFile']);
Uri goldenKey = Uri.parse(command['key']);
bool update = command['update'];
final bytes = await File(imageFile.path).readAsBytes();
if (update) {
await goldenFileComparator.update(goldenKey, bytes);
print(jsonEncode({'success': true}));
} else {
try {
bool success = await goldenFileComparator.compare(bytes, goldenKey);
print(jsonEncode({'success': success}));
} on Exception catch (ex) {
print(jsonEncode({'success': false, 'message': '
\
$ex
'}));
}
}
} else {
print('object type is not right');
}
}
${testConfigFile != null ? '}
);' : ''}
}
''';
}
}
packages/flutter_tools/lib/src/test/flutter_web_platform.dart
View file @
4832e64c
...
...
@@ -11,7 +11,6 @@ import 'package:async/async.dart';
import
'package:http_multi_server/http_multi_server.dart'
;
import
'package:meta/meta.dart'
;
import
'package:package_config/package_config.dart'
;
import
'package:path/path.dart'
as
p
;
// ignore: package_path_import
import
'package:pool/pool.dart'
;
import
'package:shelf/shelf.dart'
as
shelf
;
import
'package:shelf/shelf_io.dart'
as
shelf_io
;
...
...
@@ -26,16 +25,16 @@ import '../artifacts.dart';
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/logger.dart'
;
import
'../build_info.dart'
;
import
'../cache.dart'
;
import
'../convert.dart'
;
import
'../dart/package_map.dart'
;
import
'../globals.dart'
as
globals
;
import
'../project.dart'
;
import
'../web/chrome.dart'
;
import
'../web/memory_fs.dart'
;
import
'flutter_web_goldens.dart'
;
import
'test_compiler.dart'
;
import
'test_config.dart'
;
class
FlutterWebPlatform
extends
PlatformPlugin
{
FlutterWebPlatform
.
_
(
this
.
_server
,
this
.
_config
,
this
.
_root
,
{
...
...
@@ -44,11 +43,20 @@ class FlutterWebPlatform extends PlatformPlugin {
this
.
updateGoldens
,
@required
this
.
buildInfo
,
@required
this
.
webMemoryFS
,
})
{
@required
FileSystem
fileSystem
,
@required
PackageConfig
flutterToolPackageConfig
,
@required
ChromiumLauncher
chromiumLauncher
,
@required
Logger
logger
,
@required
Artifacts
artifacts
,
})
:
_fileSystem
=
fileSystem
,
_flutterToolPackageConfig
=
flutterToolPackageConfig
,
_chromiumLauncher
=
chromiumLauncher
,
_logger
=
logger
,
_artifacts
=
artifacts
{
final
shelf
.
Cascade
cascade
=
shelf
.
Cascade
()
.
add
(
_webSocketHandler
.
handler
)
.
add
(
createStaticHandler
(
globals
.
fs
.
path
.
join
(
Cache
.
flutterRoot
,
'packages'
,
'flutter_tools'
),
fileSystem
.
path
.
join
(
Cache
.
flutterRoot
,
'packages'
,
'flutter_tools'
),
serveFilesOutsidePath:
true
,
))
.
add
(
_handleStaticArtifact
)
...
...
@@ -56,12 +64,11 @@ class FlutterWebPlatform extends PlatformPlugin {
.
add
(
_wrapperHandler
)
.
add
(
_handleTestRequest
)
.
add
(
createStaticHandler
(
p
.
join
(
p
.
current
,
'test'
),
fileSystem
.
path
.
join
(
fileSystem
.
currentDirectory
.
path
,
'test'
),
serveFilesOutsidePath:
true
,
))
.
add
(
_packageFilesHandler
);
_server
.
mount
(
cascade
.
handler
);
_testGoldenComparator
=
TestGoldenComparator
(
shellPath
,
()
=>
TestCompiler
(
buildInfo
,
flutterProject
),
...
...
@@ -70,6 +77,11 @@ class FlutterWebPlatform extends PlatformPlugin {
final
WebMemoryFS
webMemoryFS
;
final
BuildInfo
buildInfo
;
final
FileSystem
_fileSystem
;
final
PackageConfig
_flutterToolPackageConfig
;
final
ChromiumLauncher
_chromiumLauncher
;
final
Logger
_logger
;
final
Artifacts
_artifacts
;
static
Future
<
FlutterWebPlatform
>
start
(
String
root
,
{
FlutterProject
flutterProject
,
...
...
@@ -78,8 +90,22 @@ class FlutterWebPlatform extends PlatformPlugin {
bool
pauseAfterLoad
=
false
,
@required
BuildInfo
buildInfo
,
@required
WebMemoryFS
webMemoryFS
,
@required
FileSystem
fileSystem
,
@required
Logger
logger
,
@required
ChromiumLauncher
chromiumLauncher
,
@required
Artifacts
artifacts
,
})
async
{
final
shelf_io
.
IOServer
server
=
shelf_io
.
IOServer
(
await
HttpMultiServer
.
loopback
(
0
));
final
PackageConfig
packageConfig
=
await
loadPackageConfigWithLogging
(
fileSystem
.
file
(
fileSystem
.
path
.
join
(
Cache
.
flutterRoot
,
'packages'
,
'flutter_tools'
,
'.dart_tool'
,
'package_config.json'
,
)),
logger:
logger
,
);
return
FlutterWebPlatform
.
_
(
server
,
Configuration
.
current
.
change
(
pauseAfterLoad:
pauseAfterLoad
),
...
...
@@ -89,81 +115,65 @@ class FlutterWebPlatform extends PlatformPlugin {
updateGoldens:
updateGoldens
,
buildInfo:
buildInfo
,
webMemoryFS:
webMemoryFS
,
flutterToolPackageConfig:
packageConfig
,
fileSystem:
fileSystem
,
chromiumLauncher:
chromiumLauncher
,
artifacts:
artifacts
,
logger:
logger
,
);
}
final
Future
<
PackageConfig
>
_flutterToolsPackageMap
=
loadPackageConfigWithLogging
(
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
Cache
.
flutterRoot
,
'packages'
,
'flutter_tools'
,
'.packages'
,
)),
logger:
globals
.
logger
,
);
/// Uri of the test package.
Future
<
Uri
>
get
testUri
async
=>
(
await
_flutterToolsPackageMap
)[
'test'
]?
.
packageUriRoot
;
Uri
get
testUri
=>
_flutterToolPackageConfig
[
'test'
]
.
packageUriRoot
;
/// The test runner configuration.
final
Configuration
_config
;
@visibleForTesting
Configuration
get
config
=>
_config
;
/// The underlying server.
final
shelf
.
Server
_server
;
@visibleForTesting
shelf
.
Server
get
server
=>
_server
;
/// The URL for this server.
Uri
get
url
=>
_server
.
url
;
/// The ahem text file.
File
get
ahem
=>
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
Cache
.
flutterRoot
,
'packages'
,
'flutter_tools'
,
'static'
,
'Ahem.ttf'
,
));
File
get
_ahem
=>
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
Cache
.
flutterRoot
,
'packages'
,
'flutter_tools'
,
'static'
,
'Ahem.ttf'
,
));
/// The require js binary.
File
get
requireJs
=>
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
globals
.
artifacts
.
getArtifactPath
(
Artifact
.
engineDartSdkPath
),
'lib'
,
'dev_compiler'
,
'kernel'
,
'amd'
,
'require.js'
,
));
File
get
_requireJs
=>
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
_
artifacts
.
getArtifactPath
(
Artifact
.
engineDartSdkPath
),
'lib'
,
'dev_compiler'
,
'kernel'
,
'amd'
,
'require.js'
,
));
/// The ddc to dart stack trace mapper.
File
get
stackTraceMapper
=>
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
globals
.
artifacts
.
getArtifactPath
(
Artifact
.
engineDartSdkPath
),
'lib'
,
'dev_compiler'
,
'web'
,
'dart_stack_trace_mapper.js'
,
));
File
get
_stackTraceMapper
=>
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
_
artifacts
.
getArtifactPath
(
Artifact
.
engineDartSdkPath
),
'lib'
,
'dev_compiler'
,
'web'
,
'dart_stack_trace_mapper.js'
,
));
/// The precompiled dart sdk.
File
get
dartSdk
=>
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
globals
.
artifacts
.
getArtifactPath
(
Artifact
.
flutterWebSdk
),
'kernel'
,
'amd'
,
'dart_sdk.js'
,
));
File
get
_dartSdk
=>
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
_
artifacts
.
getArtifactPath
(
Artifact
.
flutterWebSdk
),
'kernel'
,
'amd'
,
'dart_sdk.js'
,
));
/// The precompiled test javascript.
F
uture
<
File
>
get
testDartJs
async
=>
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
(
await
testUri
)
.
toFilePath
(),
F
ile
get
_testDartJs
=>
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
testUri
.
toFilePath
(),
'dart.js'
,
));
F
uture
<
File
>
get
testHostDartJs
async
=>
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
(
await
testUri
)
.
toFilePath
(),
F
ile
get
_testHostDartJs
=>
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
testUri
.
toFilePath
(),
'src'
,
'runner'
,
'browser'
,
...
...
@@ -174,15 +184,15 @@ class FlutterWebPlatform extends PlatformPlugin {
Future
<
shelf
.
Response
>
_handleTestRequest
(
shelf
.
Request
request
)
async
{
if
(
request
.
url
.
path
.
endsWith
(
'.dart.browser_test.dart.js'
))
{
final
String
leadingPath
=
request
.
url
.
path
.
split
(
'.browser_test.dart.js'
)[
0
];
final
String
generatedFile
=
globals
.
fs
.
path
.
split
(
leadingPath
).
join
(
'_'
)
+
'.bootstrap.js'
;
final
String
generatedFile
=
_fileSystem
.
path
.
split
(
leadingPath
).
join
(
'_'
)
+
'.bootstrap.js'
;
return
shelf
.
Response
.
ok
(
bootstrapFileContents
(
'/'
+
generatedFile
,
'require.js'
,
'dart_stack_trace_mapper.js'
),
headers:
<
String
,
String
>{
HttpHeaders
.
contentTypeHeader
:
'text/javascript'
,
});
}
if
(
request
.
url
.
path
.
endsWith
(
'.dart.bootstrap.js'
))
{
final
String
leadingPath
=
request
.
url
.
path
.
split
(
'.dart.bootstrap.js'
)[
0
];
final
String
generatedFile
=
globals
.
fs
.
path
.
split
(
leadingPath
).
join
(
'_'
)
+
'.dart.test.dart.js'
;
return
shelf
.
Response
.
ok
(
generatedActualMain
(
globals
.
fs
.
path
.
basename
(
leadingPath
)
+
'.dart.bootstrap'
,
'/'
+
generatedFile
),
headers:
<
String
,
String
>{
final
String
generatedFile
=
_fileSystem
.
path
.
split
(
leadingPath
).
join
(
'_'
)
+
'.dart.test.dart.js'
;
return
shelf
.
Response
.
ok
(
generatedActualMain
(
_fileSystem
.
path
.
basename
(
leadingPath
)
+
'.dart.bootstrap'
,
'/'
+
generatedFile
),
headers:
<
String
,
String
>{
HttpHeaders
.
contentTypeHeader
:
'text/javascript'
,
});
}
...
...
@@ -203,30 +213,30 @@ class FlutterWebPlatform extends PlatformPlugin {
Future
<
shelf
.
Response
>
_handleStaticArtifact
(
shelf
.
Request
request
)
async
{
if
(
request
.
requestedUri
.
path
.
contains
(
'require.js'
))
{
return
shelf
.
Response
.
ok
(
requireJs
.
openRead
(),
_
requireJs
.
openRead
(),
headers:
<
String
,
String
>{
'Content-Type'
:
'text/javascript'
},
);
}
else
if
(
request
.
requestedUri
.
path
.
contains
(
'ahem.ttf'
))
{
return
shelf
.
Response
.
ok
(
ahem
.
openRead
());
return
shelf
.
Response
.
ok
(
_
ahem
.
openRead
());
}
else
if
(
request
.
requestedUri
.
path
.
contains
(
'dart_sdk.js'
))
{
return
shelf
.
Response
.
ok
(
dartSdk
.
openRead
(),
_
dartSdk
.
openRead
(),
headers:
<
String
,
String
>{
'Content-Type'
:
'text/javascript'
},
);
}
else
if
(
request
.
requestedUri
.
path
.
contains
(
'dart_stack_trace_mapper.js'
))
{
return
shelf
.
Response
.
ok
(
stackTraceMapper
.
openRead
(),
_
stackTraceMapper
.
openRead
(),
headers:
<
String
,
String
>{
'Content-Type'
:
'text/javascript'
},
);
}
else
if
(
request
.
requestedUri
.
path
.
contains
(
'static/dart.js'
))
{
return
shelf
.
Response
.
ok
(
(
await
testDartJs
)
.
openRead
(),
_testDartJs
.
openRead
(),
headers:
<
String
,
String
>{
'Content-Type'
:
'text/javascript'
},
);
}
else
if
(
request
.
requestedUri
.
path
.
contains
(
'host.dart.js'
))
{
return
shelf
.
Response
.
ok
(
(
await
testHostDartJs
)
.
openRead
(),
_testHostDartJs
.
openRead
(),
headers:
<
String
,
String
>{
'Content-Type'
:
'text/javascript'
},
);
}
else
{
...
...
@@ -241,8 +251,8 @@ class FlutterWebPlatform extends PlatformPlugin {
pathSegments:
request
.
requestedUri
.
pathSegments
.
skip
(
1
),
));
if
(
fileUri
!=
null
)
{
final
String
dirname
=
p
.
dirname
(
fileUri
.
toFilePath
());
final
String
basename
=
p
.
basename
(
fileUri
.
toFilePath
());
final
String
dirname
=
_fileSystem
.
path
.
dirname
(
fileUri
.
toFilePath
());
final
String
basename
=
_fileSystem
.
path
.
basename
(
fileUri
.
toFilePath
());
final
shelf
.
Handler
handler
=
createStaticHandler
(
dirname
);
final
shelf
.
Request
modifiedRequest
=
shelf
.
Request
(
request
.
method
,
...
...
@@ -293,10 +303,10 @@ class FlutterWebPlatform extends PlatformPlugin {
});
bytes
=
base64
.
decode
(
response
.
result
[
'data'
]
as
String
);
}
on
WipError
catch
(
ex
)
{
globals
.
printError
(
'Caught WIPError:
$ex
'
);
_logger
.
printError
(
'Caught WIPError:
$ex
'
);
return
shelf
.
Response
.
ok
(
'WIP error:
$ex
'
);
}
on
FormatException
catch
(
ex
)
{
globals
.
printError
(
'Caught FormatException:
$ex
'
);
_logger
.
printError
(
'Caught FormatException:
$ex
'
);
return
shelf
.
Response
.
ok
(
'Caught exception:
$ex
'
);
}
...
...
@@ -321,10 +331,10 @@ class FlutterWebPlatform extends PlatformPlugin {
// A handler that serves wrapper files used to bootstrap tests.
shelf
.
Response
_wrapperHandler
(
shelf
.
Request
request
)
{
final
String
path
=
globals
.
fs
.
path
.
fromUri
(
request
.
url
);
final
String
path
=
_fileSystem
.
path
.
fromUri
(
request
.
url
);
if
(
path
.
endsWith
(
'.html'
))
{
final
String
test
=
globals
.
fs
.
path
.
withoutExtension
(
path
)
+
'.dart'
;
final
String
scriptBase
=
htmlEscape
.
convert
(
globals
.
fs
.
path
.
basename
(
test
));
final
String
test
=
_fileSystem
.
path
.
withoutExtension
(
path
)
+
'.dart'
;
final
String
scriptBase
=
htmlEscape
.
convert
(
_fileSystem
.
path
.
basename
(
test
));
final
String
link
=
'<link rel="x-dart-test" href="
$scriptBase
">'
;
return
shelf
.
Response
.
ok
(
'''
<!DOCTYPE html>
...
...
@@ -369,10 +379,9 @@ class FlutterWebPlatform extends PlatformPlugin {
throw
StateError
(
'Load called on a closed FlutterWebPlatform'
);
}
final
Uri
suiteUrl
=
url
.
resolveUri
(
globals
.
fs
.
path
.
toUri
(
globals
.
fs
.
path
.
withoutExtension
(
globals
.
fs
.
path
.
relative
(
path
,
from:
globals
.
fs
.
path
.
join
(
_root
,
'test'
)))
+
'.html'
));
final
String
relativePath
=
globals
.
fs
.
path
.
relative
(
globals
.
fs
.
path
.
normalize
(
path
),
from:
globals
.
fs
.
currentDirectory
.
path
);
final
Uri
suiteUrl
=
url
.
resolveUri
(
_fileSystem
.
path
.
toUri
(
_fileSystem
.
path
.
withoutExtension
(
_fileSystem
.
path
.
relative
(
path
,
from:
_fileSystem
.
path
.
join
(
_root
,
'test'
)))
+
'.html'
));
final
String
relativePath
=
_fileSystem
.
path
.
relative
(
_fileSystem
.
path
.
normalize
(
path
),
from:
_fileSystem
.
currentDirectory
.
path
);
final
RunnerSuite
suite
=
await
_browserManager
.
load
(
relativePath
,
suiteUrl
,
suiteConfig
,
message
,
onDone:
()
async
{
await
_browserManager
.
close
();
_browserManager
=
null
;
...
...
@@ -406,9 +415,10 @@ class FlutterWebPlatform extends PlatformPlugin {
'debug'
:
_config
.
pauseAfterLoad
.
toString
(),
});
globals
.
printTrace
(
'Serving tests at
$hostUrl
'
);
_logger
.
printTrace
(
'Serving tests at
$hostUrl
'
);
return
BrowserManager
.
start
(
_chromiumLauncher
,
browser
,
hostUrl
,
completer
.
future
,
...
...
@@ -459,7 +469,7 @@ class OneOffHandler {
/// Dispatches [request] to the appropriate handler.
FutureOr
<
shelf
.
Response
>
_onRequest
(
shelf
.
Request
request
)
{
final
List
<
String
>
components
=
p
.
url
.
split
(
request
.
url
.
path
);
final
List
<
String
>
components
=
request
.
url
.
path
.
split
(
'/'
);
if
(
components
.
isEmpty
)
{
return
shelf
.
Response
.
notFound
(
null
);
}
...
...
@@ -513,10 +523,6 @@ class BrowserManager {
/// The browser instance that this is connected to via [_channel].
final
Chromium
_browser
;
// TODO(nweiz): Consider removing the duplication between this and
// [_browser.name].
/// The [Runtime] for [_browser].
final
Runtime
_runtime
;
/// The channel used to communicate with the browser.
...
...
@@ -574,23 +580,14 @@ class BrowserManager {
/// Returns the browser manager, or throws an [ApplicationException] if a
/// connection fails to be established.
static
Future
<
BrowserManager
>
start
(
ChromiumLauncher
chromiumLauncher
,
Runtime
runtime
,
Uri
url
,
Future
<
WebSocketChannel
>
future
,
{
bool
debug
=
false
,
bool
headless
=
true
,
})
async
{
final
ChromiumLauncher
chromiumLauncher
=
ChromiumLauncher
(
browserFinder:
findChromeExecutable
,
fileSystem:
globals
.
fs
,
operatingSystemUtils:
globals
.
os
,
platform:
globals
.
platform
,
processManager:
globals
.
processManager
,
logger:
globals
.
logger
,
);
final
Chromium
chrome
=
await
chromiumLauncher
.
launch
(
url
.
toString
(),
headless:
headless
);
final
Chromium
chrome
=
await
chromiumLauncher
.
launch
(
url
.
toString
(),
headless:
headless
);
final
Completer
<
BrowserManager
>
completer
=
Completer
<
BrowserManager
>();
unawaited
(
chrome
.
onExit
.
then
((
int
browserExitCode
)
{
...
...
@@ -773,186 +770,6 @@ class _BrowserEnvironment implements Environment {
CancelableOperation
<
dynamic
>
displayPause
()
=>
_manager
.
_displayPause
();
}
/// Helper class to start golden file comparison in a separate process.
///
/// Golden file comparator is configured using flutter_test_config.dart and that
/// file can contain arbitrary Dart code that depends on dart:ui. Thus it has to
/// be executed in a `flutter_tester` environment. This helper class generates a
/// Dart file configured with flutter_test_config.dart to perform the comparison
/// of golden files.
class
TestGoldenComparator
{
/// Creates a [TestGoldenComparator] instance.
TestGoldenComparator
(
this
.
shellPath
,
this
.
compilerFactory
)
:
tempDir
=
globals
.
fs
.
systemTempDirectory
.
createTempSync
(
'flutter_web_platform.'
);
final
String
shellPath
;
final
Directory
tempDir
;
final
TestCompiler
Function
()
compilerFactory
;
TestCompiler
_compiler
;
TestGoldenComparatorProcess
_previousComparator
;
Uri
_previousTestUri
;
Future
<
void
>
close
()
async
{
tempDir
.
deleteSync
(
recursive:
true
);
await
_compiler
?.
dispose
();
await
_previousComparator
?.
close
();
}
/// Start golden comparator in a separate process. Start one file per test file
/// to reduce the overhead of starting `flutter_tester`.
Future
<
TestGoldenComparatorProcess
>
_processForTestFile
(
Uri
testUri
)
async
{
if
(
testUri
==
_previousTestUri
)
{
return
_previousComparator
;
}
final
String
bootstrap
=
TestGoldenComparatorProcess
.
generateBootstrap
(
testUri
);
final
Process
process
=
await
_startProcess
(
bootstrap
);
unawaited
(
_previousComparator
?.
close
());
_previousComparator
=
TestGoldenComparatorProcess
(
process
);
_previousTestUri
=
testUri
;
return
_previousComparator
;
}
Future
<
Process
>
_startProcess
(
String
testBootstrap
)
async
{
// Prepare the Dart file that will talk to us and start the test.
final
File
listenerFile
=
(
await
tempDir
.
createTemp
(
'listener'
)).
childFile
(
'listener.dart'
);
await
listenerFile
.
writeAsString
(
testBootstrap
);
// Lazily create the compiler
_compiler
=
_compiler
??
compilerFactory
();
final
String
output
=
await
_compiler
.
compile
(
listenerFile
.
uri
);
final
List
<
String
>
command
=
<
String
>[
shellPath
,
'--disable-observatory'
,
'--non-interactive'
,
'--packages=
${globals.fs.path.join('.dart_tool', 'package_config.json')}
'
,
output
,
];
final
Map
<
String
,
String
>
environment
=
<
String
,
String
>{
// Chrome is the only supported browser currently.
'FLUTTER_TEST_BROWSER'
:
'chrome'
,
};
return
globals
.
processManager
.
start
(
command
,
environment:
environment
);
}
Future
<
String
>
compareGoldens
(
Uri
testUri
,
Uint8List
bytes
,
Uri
goldenKey
,
bool
updateGoldens
)
async
{
final
File
imageFile
=
await
(
await
tempDir
.
createTemp
(
'image'
)).
childFile
(
'image'
).
writeAsBytes
(
bytes
);
final
TestGoldenComparatorProcess
process
=
await
_processForTestFile
(
testUri
);
process
.
sendCommand
(
imageFile
,
goldenKey
,
updateGoldens
);
final
Map
<
String
,
dynamic
>
result
=
await
process
.
getResponse
();
if
(
result
==
null
)
{
return
'unknown error'
;
}
else
{
return
(
result
[
'success'
]
as
bool
)
?
null
:
((
result
[
'message'
]
as
String
)
??
'does not match'
);
}
}
}
/// Represents a `flutter_tester` process started for golden comparison. Also
/// handles communication with the child process.
class
TestGoldenComparatorProcess
{
/// Creates a [TestGoldenComparatorProcess] backed by [process].
TestGoldenComparatorProcess
(
this
.
process
)
{
// Pipe stdout and stderr to printTrace and printError.
// Also parse stdout as a stream of JSON objects.
streamIterator
=
StreamIterator
<
Map
<
String
,
dynamic
>>(
process
.
stdout
.
transform
<
String
>(
utf8
.
decoder
)
.
transform
<
String
>(
const
LineSplitter
())
.
where
((
String
line
)
{
globals
.
printTrace
(
'<<<
$line
'
);
return
line
.
isNotEmpty
&&
line
[
0
]
==
'{'
;
})
.
map
<
dynamic
>(
jsonDecode
)
.
cast
<
Map
<
String
,
dynamic
>>());
process
.
stderr
.
transform
<
String
>(
utf8
.
decoder
)
.
transform
<
String
>(
const
LineSplitter
())
.
forEach
((
String
line
)
{
globals
.
printError
(
'<<<
$line
'
);
});
}
final
Process
process
;
StreamIterator
<
Map
<
String
,
dynamic
>>
streamIterator
;
Future
<
void
>
close
()
async
{
await
process
.
stdin
.
close
();
process
.
kill
();
}
void
sendCommand
(
File
imageFile
,
Uri
goldenKey
,
bool
updateGoldens
)
{
final
Object
command
=
jsonEncode
(<
String
,
dynamic
>{
'imageFile'
:
imageFile
.
path
,
'key'
:
goldenKey
.
toString
(),
'update'
:
updateGoldens
,
});
globals
.
printTrace
(
'Preparing to send command:
$command
'
);
process
.
stdin
.
writeln
(
command
);
}
Future
<
Map
<
String
,
dynamic
>>
getResponse
()
async
{
final
bool
available
=
await
streamIterator
.
moveNext
();
assert
(
available
);
return
streamIterator
.
current
;
}
static
String
generateBootstrap
(
Uri
testUri
)
{
final
File
testConfigFile
=
findTestConfigFile
(
globals
.
fs
.
file
(
testUri
));
// Generate comparator process for the file.
return
'''
// @dart=2.9
import '
dart:
convert
'; // ignore: dart_convert_import
import '
dart:
io
'; // ignore: dart_io_import
import '
package:
flutter_test
/
flutter_test
.
dart
';
${testConfigFile != null ? "import '${Uri.file(testConfigFile.path)}
'
as
test_config
;
" : ""}
void main() async {
LocalFileComparator comparator = LocalFileComparator(Uri.parse('
$testUri
'));
goldenFileComparator = comparator;
${testConfigFile != null ? 'test_config.testExecutable(() async {' : ''}
final commands = stdin
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
.map<Object>(jsonDecode);
await for (final Object command in commands) {
if (command is Map<String, dynamic>) {
File imageFile = File(command['imageFile']);
Uri goldenKey = Uri.parse(command['key']);
bool update = command['update'];
final bytes = await File(imageFile.path).readAsBytes();
if (update) {
await goldenFileComparator.update(goldenKey, bytes);
print(jsonEncode({'success': true}));
} else {
try {
bool success = await goldenFileComparator.compare(bytes, goldenKey);
print(jsonEncode({'success': success}));
} on Exception catch (ex) {
print(jsonEncode({'success': false, 'message': '
\
$ex
'}));
}
}
} else {
print('object type is not right');
}
}
${testConfigFile != null ? '}
);' : ''}
}
''';
}
}
String
bootstrapFileContents
(
String
mainUri
,
String
requireUrl
,
String
mapperUrl
)
{
return
'''
(function() {
...
...
packages/flutter_tools/lib/src/test/runner.dart
View file @
4832e64c
...
...
@@ -11,6 +11,7 @@ import '../base/io.dart';
import
'../build_info.dart'
;
import
'../globals.dart'
as
globals
;
import
'../project.dart'
;
import
'../web/chrome.dart'
;
import
'../web/compile.dart'
;
import
'../web/memory_fs.dart'
;
import
'flutter_platform.dart'
as
loader
;
...
...
@@ -139,6 +140,8 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
testWrapper
.
registerPlatformPlugin
(
<
Runtime
>[
Runtime
.
chrome
],
()
{
// TODO(jonahwilliams): refactor this into a factory that handles
// providing dependencies.
return
FlutterWebPlatform
.
start
(
flutterProject
.
directory
.
path
,
updateGoldens:
updateGoldens
,
...
...
@@ -147,6 +150,17 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
pauseAfterLoad:
startPaused
,
buildInfo:
buildInfo
,
webMemoryFS:
result
,
logger:
globals
.
logger
,
fileSystem:
globals
.
fs
,
artifacts:
globals
.
artifacts
,
chromiumLauncher:
ChromiumLauncher
(
fileSystem:
globals
.
fs
,
platform:
globals
.
platform
,
processManager:
globals
.
processManager
,
operatingSystemUtils:
globals
.
os
,
browserFinder:
findChromeExecutable
,
logger:
globals
.
logger
,
),
);
},
);
...
...
packages/flutter_tools/test/general.shard/web/golden_comparator_process_test.dart
View file @
4832e64c
...
...
@@ -5,8 +5,8 @@
import
'dart:convert'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/test/flutter_web_platform.dart'
;
import
'package:flutter_tools/src/globals.dart'
as
globals
;
import
'package:flutter_tools/src/test/flutter_web_goldens.dart'
;
import
'../../src/common.dart'
;
import
'../../src/mocks.dart'
;
...
...
packages/flutter_tools/test/general.shard/web/golden_comparator_test.dart
View file @
4832e64c
...
...
@@ -5,7 +5,7 @@
import
'dart:convert'
;
import
'dart:typed_data'
;
import
'package:flutter_tools/src/test/flutter_web_
platform
.dart'
;
import
'package:flutter_tools/src/test/flutter_web_
goldens
.dart'
;
import
'package:flutter_tools/src/test/test_compiler.dart'
;
import
'package:flutter_tools/src/globals.dart'
as
globals
;
import
'package:mockito/mockito.dart'
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment