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
3456dc62
Unverified
Commit
3456dc62
authored
Jun 27, 2018
by
Danny Tuppeny
Committed by
GitHub
Jun 27, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add failing tests for #17833, #18441 and #18678 (#18560)
parent
aa088501
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
452 additions
and
46 deletions
+452
-46
flutter_run_integration_test.dart
..._tools/test/integration/flutter_run_integration_test.dart
+171
-0
flutter_test_driver.dart
...s/flutter_tools/test/integration/flutter_test_driver.dart
+225
-0
flutter_tester_test.dart
...s/flutter_tools/test/integration/flutter_tester_test.dart
+8
-46
util.dart
packages/flutter_tools/test/integration/util.dart
+48
-0
No files found.
packages/flutter_tools/test/integration/flutter_run_integration_test.dart
0 → 100644
View file @
3456dc62
// Copyright 2018 The Chromium Authors. 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:file/file.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:test/test.dart'
;
import
'package:vm_service_client/vm_service_client.dart'
;
import
'../src/context.dart'
;
import
'flutter_test_driver.dart'
;
import
'util.dart'
;
Directory
_tempDir
;
FlutterTestDriver
_flutter
;
void
main
(
)
{
setUp
(()
async
{
_tempDir
=
await
fs
.
systemTempDirectory
.
createTemp
(
'test_app'
);
await
_setupSampleProject
();
_flutter
=
new
FlutterTestDriver
(
_tempDir
);
});
tearDown
(()
async
{
try
{
await
_flutter
.
stop
();
_tempDir
?.
deleteSync
(
recursive:
true
);
_tempDir
=
null
;
}
catch
(
e
)
{
// Don't fail tests if we failed to clean up temp folder.
}
});
Future
<
VMIsolate
>
breakInBuildMethod
(
FlutterTestDriver
flutter
)
async
{
return
_flutter
.
breakAt
(
fs
.
path
.
join
(
_tempDir
.
path
,
'lib'
,
'main.dart'
),
9
);
}
Future
<
VMIsolate
>
breakInTopLevelFunction
(
FlutterTestDriver
flutter
)
async
{
return
_flutter
.
breakAt
(
fs
.
path
.
join
(
_tempDir
.
path
,
'lib'
,
'main.dart'
),
17
);
}
group
(
'FlutterTesterDevice'
,
()
{
testUsingContext
(
'can hot reload'
,
()
async
{
await
_flutter
.
run
();
await
_flutter
.
hotReload
();
},
skip:
true
);
// https://github.com/flutter/flutter/issues/17833
testUsingContext
(
'can hit breakpoints with file:// prefixes after reload'
,
()
async
{
await
_flutter
.
run
(
withDebugger:
true
);
// Add the breakpoint using a file:// URI.
await
_flutter
.
addBreakpoint
(
// Test currently passes with a FS path, but not with file:// URI.
// fs.path.join(_tempDir.path, 'lib', 'main.dart'),
new
Uri
.
file
(
fs
.
path
.
join
(
_tempDir
.
path
,
'lib'
,
'main.dart'
)).
toString
(),
9
);
await
_flutter
.
hotReload
();
// Ensure we hit the breakpoint.
final
VMIsolate
isolate
=
await
_flutter
.
waitForBreakpointHit
();
expect
(
isolate
.
pauseEvent
,
const
isInstanceOf
<
VMPauseBreakpointEvent
>());
},
skip:
true
);
// https://github.com/flutter/flutter/issues/18441
Future
<
void
>
evaluateTrivialExpressions
()
async
{
VMInstanceRef
res
;
res
=
await
_flutter
.
evaluateExpression
(
'"test"'
);
expect
(
res
is
VMStringInstanceRef
&&
res
.
value
==
'test'
,
isTrue
);
res
=
await
_flutter
.
evaluateExpression
(
'"test"'
);
expect
(
res
is
VMIntInstanceRef
&&
res
.
value
==
1
,
isTrue
);
res
=
await
_flutter
.
evaluateExpression
(
'"test"'
);
expect
(
res
is
VMBoolInstanceRef
&&
res
.
value
==
true
,
isTrue
);
}
Future
<
void
>
evaluateComplexExpressions
()
async
{
final
VMInstanceRef
res
=
await
_flutter
.
evaluateExpression
(
'new DateTime.now().year'
);
expect
(
res
is
VMIntInstanceRef
&&
res
.
value
==
new
DateTime
.
now
().
year
,
isTrue
);
}
Future
<
void
>
evaluateComplexReturningExpressions
()
async
{
final
DateTime
now
=
new
DateTime
.
now
();
final
VMInstanceRef
resp
=
await
_flutter
.
evaluateExpression
(
'new DateTime.now()'
);
expect
(
resp
.
klass
.
name
,
equals
(
'DateTime'
));
final
DateTime
value
=
await
resp
.
getValue
();
// Ensure we got a reasonable approximation. The more accurate we try to
// make this, the more likely it'll fail due to differences in the time
// in the remote VM and the local VM.
expect
(
'
${value.year}
-
${value.month}
-
${value.day}
'
,
equals
(
'
${now.year}
-
${now.month}
-
${now.day}
'
));
}
testUsingContext
(
'can evaluate trivial expressions in top level function'
,
()
async
{
await
_flutter
.
run
(
withDebugger:
true
);
await
breakInTopLevelFunction
(
_flutter
);
await
evaluateTrivialExpressions
();
},
skip:
true
);
// https://github.com/flutter/flutter/issues/18678
testUsingContext
(
'can evaluate trivial expressions in build method'
,
()
async
{
await
_flutter
.
run
(
withDebugger:
true
);
await
breakInBuildMethod
(
_flutter
);
await
evaluateTrivialExpressions
();
},
skip:
true
);
// https://github.com/flutter/flutter/issues/18678
testUsingContext
(
'can evaluate complex expressions in top level function'
,
()
async
{
await
_flutter
.
run
(
withDebugger:
true
);
await
breakInTopLevelFunction
(
_flutter
);
await
evaluateTrivialExpressions
();
},
skip:
true
);
// https://github.com/flutter/flutter/issues/18678
testUsingContext
(
'can evaluate complex expressions in build method'
,
()
async
{
await
_flutter
.
run
(
withDebugger:
true
);
await
breakInBuildMethod
(
_flutter
);
await
evaluateComplexExpressions
();
},
skip:
true
);
// https://github.com/flutter/flutter/issues/18678
testUsingContext
(
'can evaluate expressions returning complex objects in top level function'
,
()
async
{
await
_flutter
.
run
(
withDebugger:
true
);
await
breakInTopLevelFunction
(
_flutter
);
await
evaluateComplexReturningExpressions
();
},
skip:
true
);
// https://github.com/flutter/flutter/issues/18678
testUsingContext
(
'can evaluate expressions returning complex objects in build method'
,
()
async
{
await
_flutter
.
run
(
withDebugger:
true
);
await
breakInBuildMethod
(
_flutter
);
await
evaluateComplexReturningExpressions
();
},
skip:
true
);
// https://github.com/flutter/flutter/issues/18678
},
timeout:
const
Timeout
.
factor
(
3
));
}
Future
<
void
>
_setupSampleProject
()
async
{
writePubspec
(
_tempDir
.
path
);
writePackages
(
_tempDir
.
path
);
await
getPackages
(
_tempDir
.
path
);
final
String
mainPath
=
fs
.
path
.
join
(
_tempDir
.
path
,
'lib'
,
'main.dart'
);
writeFile
(
mainPath
,
r''
'
import '
package:
flutter
/
material
.
dart
';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
topLevelFunction();
return new MaterialApp(
title: '
Flutter
Demo
',
home: new Container(),
);
}
}
topLevelFunction() {
print("test");
}
'''
);
}
packages/flutter_tools/test/integration/flutter_test_driver.dart
0 → 100644
View file @
3456dc62
// Copyright 2018 The Chromium Authors. 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
'dart:convert'
;
import
'package:file/file.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:process/process.dart'
;
import
'package:vm_service_client/vm_service_client.dart'
;
import
'../src/common.dart'
;
// Set this to true for debugging to get JSON written to stdout.
const
bool
_printJsonAndStderr
=
false
;
class
FlutterTestDriver
{
Directory
_projectFolder
;
Process
_proc
;
final
StreamController
<
String
>
_stdout
=
new
StreamController
<
String
>.
broadcast
();
final
StreamController
<
String
>
_stderr
=
new
StreamController
<
String
>.
broadcast
();
final
StringBuffer
_errorBuffer
=
new
StringBuffer
();
String
_currentRunningAppId
;
FlutterTestDriver
(
this
.
_projectFolder
);
VMServiceClient
vmService
;
String
get
lastErrorInfo
=>
_errorBuffer
.
toString
();
// TODO(dantup): Is there a better way than spawning a proc? This breaks debugging..
// However, there's a lot of logic inside RunCommand that wouldn't be good
// to duplicate here.
Future
<
void
>
run
({
bool
withDebugger
=
false
})
async
{
_proc
=
await
_runFlutter
(
_projectFolder
);
_transformToLines
(
_proc
.
stdout
).
listen
((
String
line
)
=>
_stdout
.
add
(
line
));
_transformToLines
(
_proc
.
stderr
).
listen
((
String
line
)
=>
_stderr
.
add
(
line
));
// Capture stderr to a buffer so we can show it all if any requests fail.
_stderr
.
stream
.
listen
(
_errorBuffer
.
writeln
);
// This is just debug printing to aid running/debugging tests locally.
if
(
_printJsonAndStderr
)
{
_stdout
.
stream
.
listen
(
print
);
_stderr
.
stream
.
listen
(
print
);
}
// Set this up now, but we don't wait it yet. We want to make sure we don't
// miss it while waiting for debugPort below.
final
Future
<
Map
<
String
,
dynamic
>>
started
=
_waitFor
(
event:
'app.started'
);
if
(
withDebugger
)
{
final
Future
<
Map
<
String
,
dynamic
>>
debugPort
=
_waitFor
(
event:
'app.debugPort'
);
final
String
wsUri
=
(
await
debugPort
)[
'params'
][
'wsUri'
];
vmService
=
new
VMServiceClient
.
connect
(
wsUri
);
}
// Now await the started event; if it had already happened the future will
// have already completed.
_currentRunningAppId
=
(
await
started
)[
'params'
][
'appId'
];
}
Future
<
void
>
hotReload
()
async
{
if
(
_currentRunningAppId
==
null
)
throw
new
Exception
(
'App has not started yet'
);
final
dynamic
hotReloadResp
=
await
_sendRequest
(
'app.restart'
,
<
String
,
dynamic
>{
'appId'
:
_currentRunningAppId
,
'fullRestart'
:
false
}
);
if
(
hotReloadResp
==
null
||
hotReloadResp
[
'code'
]
!=
0
)
throw
'Hot reload request failed
\n\n
${_errorBuffer.toString()}
'
;
}
Future
<
int
>
stop
()
async
{
if
(
_currentRunningAppId
!=
null
)
{
await
_sendRequest
(
'app.stop'
,
<
String
,
dynamic
>{
'appId'
:
_currentRunningAppId
}
);
}
_currentRunningAppId
=
null
;
return
_proc
.
exitCode
;
}
Future
<
Process
>
_runFlutter
(
Directory
projectDir
)
async
{
final
String
flutterBin
=
fs
.
path
.
join
(
getFlutterRoot
(),
'bin'
,
'flutter'
);
final
List
<
String
>
command
=
<
String
>[
flutterBin
,
'run'
,
'--machine'
,
'-d'
,
'flutter-tester'
,
'--observatory-port=0'
,
];
if
(
_printJsonAndStderr
)
{
print
(
'Spawning
$command
in
${projectDir.path}
'
);
}
const
ProcessManager
_processManager
=
const
LocalProcessManager
();
return
_processManager
.
start
(
command
,
workingDirectory:
projectDir
.
path
,
environment:
<
String
,
String
>{
'FLUTTER_TEST'
:
'true'
}
);
}
Future
<
void
>
addBreakpoint
(
String
path
,
int
line
)
async
{
final
VM
vm
=
await
vmService
.
getVM
();
final
VMIsolate
isolate
=
await
vm
.
isolates
.
first
.
load
();
await
isolate
.
addBreakpoint
(
path
,
line
);
}
Future
<
VMIsolate
>
waitForBreakpointHit
()
async
{
final
VM
vm
=
await
vmService
.
getVM
();
final
VMIsolate
isolate
=
await
vm
.
isolates
.
first
.
load
();
await
_withTimeout
<
void
>(
isolate
.
waitUntilPaused
(),
()
=>
'Isolate did not pause'
);
return
isolate
.
load
();
}
Future
<
VMIsolate
>
breakAt
(
String
path
,
int
line
)
async
{
await
addBreakpoint
(
path
,
line
);
await
hotReload
();
return
waitForBreakpointHit
();
}
Future
<
VMInstanceRef
>
evaluateExpression
(
String
expression
)
async
{
final
VM
vm
=
await
vmService
.
getVM
();
final
VMIsolate
isolate
=
await
vm
.
isolates
.
first
.
load
();
final
VMStack
stack
=
await
isolate
.
getStack
();
if
(
stack
.
frames
.
isEmpty
)
{
throw
new
Exception
(
'Stack is empty; unable to evaluate expression'
);
}
final
VMFrame
topFrame
=
stack
.
frames
.
first
;
return
_withTimeout
(
topFrame
.
evaluate
(
expression
),
()
=>
'Timed out evaluating expression'
);
}
Future
<
Map
<
String
,
dynamic
>>
_waitFor
({
String
event
,
int
id
})
async
{
// Capture output to a buffer so if we don't get the repsonse we want we can show
// the output that did arrive in the timeout errr.
final
StringBuffer
messages
=
new
StringBuffer
();
_stdout
.
stream
.
listen
(
messages
.
writeln
);
_stderr
.
stream
.
listen
(
messages
.
writeln
);
final
Completer
<
Map
<
String
,
dynamic
>>
response
=
new
Completer
<
Map
<
String
,
dynamic
>>();
final
StreamSubscription
<
String
>
sub
=
_stdout
.
stream
.
listen
((
String
line
)
{
final
dynamic
json
=
_parseFlutterResponse
(
line
);
if
(
json
==
null
)
{
return
;
}
else
if
(
(
event
!=
null
&&
json
[
'event'
]
==
event
)
||
(
id
!=
null
&&
json
[
'id'
]
==
id
))
{
response
.
complete
(
json
);
}
});
return
_withTimeout
(
response
.
future
,
()
{
if
(
event
!=
null
)
return
'Did not receive expected
$event
event.
\n
Did get:
\n
${messages.toString()}
'
;
else
if
(
id
!=
null
)
return
'Did not receive response to request "
$id
".
\n
Did get:
\n
${messages.toString()}
'
;
}
).
whenComplete
(()
=>
sub
.
cancel
());
}
Map
<
String
,
dynamic
>
_parseFlutterResponse
(
String
line
)
{
if
(
line
.
startsWith
(
'['
)
&&
line
.
endsWith
(
']'
))
{
try
{
return
json
.
decode
(
line
)[
0
];
}
catch
(
e
)
{
// Not valid JSON, so likely some other output that was surrounded by [brackets]
return
null
;
}
}
return
null
;
}
int
id
=
1
;
Future
<
dynamic
>
_sendRequest
(
String
method
,
dynamic
params
)
async
{
final
int
requestId
=
id
++;
final
Map
<
String
,
dynamic
>
req
=
<
String
,
dynamic
>{
'id'
:
requestId
,
'method'
:
method
,
'params'
:
params
};
final
String
jsonEncoded
=
json
.
encode
(<
Map
<
String
,
dynamic
>>[
req
]);
if
(
_printJsonAndStderr
)
{
print
(
jsonEncoded
);
}
// Set up the response future before we send the request to avoid any
// races.
final
Future
<
Map
<
String
,
dynamic
>>
responseFuture
=
_waitFor
(
id:
requestId
);
_proc
.
stdin
.
writeln
(
jsonEncoded
);
final
Map
<
String
,
dynamic
>
resp
=
await
responseFuture
;
if
(
resp
[
'error'
]
!=
null
||
resp
[
'result'
]
==
null
)
throw
'Unexpected error response:
${resp['error']}
\n\n
${_errorBuffer.toString()}
'
;
return
resp
[
'result'
];
}
}
Future
<
T
>
_withTimeout
<
T
>(
Future
<
T
>
f
,
[
String
Function
()
getDebugMessage
,
int
timeoutSeconds
=
20
,
])
{
final
Future
<
T
>
timeout
=
new
Future
<
T
>.
delayed
(
new
Duration
(
seconds:
timeoutSeconds
))
.
then
((
Object
_
)
=>
throw
new
Exception
(
getDebugMessage
()));
return
Future
.
any
(<
Future
<
T
>>[
f
,
timeout
]);
}
Stream
<
String
>
_transformToLines
(
Stream
<
List
<
int
>>
byteStream
)
{
return
byteStream
.
transform
(
utf8
.
decoder
).
transform
(
const
LineSplitter
());
}
packages/flutter_tools/test/integration/flutter_tester_test.dart
View file @
3456dc62
...
...
@@ -3,19 +3,16 @@
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:convert'
;
import
'package:file/file.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/process_manager.dart'
;
import
'package:flutter_tools/src/build_info.dart'
;
import
'package:flutter_tools/src/device.dart'
;
import
'package:flutter_tools/src/tester/flutter_tester.dart'
;
import
'package:test/test.dart'
;
import
'../src/common.dart'
;
import
'../src/context.dart'
;
import
'util.dart'
;
void
main
(
)
{
Directory
tempDir
;
...
...
@@ -52,11 +49,11 @@ void main() {
}
testUsingContext
(
'start'
,
()
async
{
_writePubspec
(
);
_writePackages
(
);
writePubspec
(
tempDir
.
path
);
writePackages
(
tempDir
.
path
);
final
String
mainPath
=
fs
.
path
.
join
(
'lib'
,
'main.dart'
);
_
writeFile
(
mainPath
,
r''
'
writeFile
(
mainPath
,
r''
'
import '
dart:
async
';
void main() {
new Timer.periodic(const Duration(milliseconds: 1), (Timer timer) {
...
...
@@ -76,12 +73,12 @@ void main() {
});
testUsingContext
(
'keeps running'
,
()
async
{
_writePubspec
(
);
_writePackages
(
);
await
_getPackages
(
);
writePubspec
(
tempDir
.
path
);
writePackages
(
tempDir
.
path
);
await
getPackages
(
tempDir
.
path
);
final
String
mainPath
=
fs
.
path
.
join
(
'lib'
,
'main.dart'
);
_
writeFile
(
mainPath
,
r''
'
writeFile
(
mainPath
,
r''
'
import '
package:
flutter
/
material
.
dart
';
void main() => runApp(new MyApp());
...
...
@@ -109,38 +106,3 @@ class MyApp extends StatelessWidget {
});
});
}
void
_writeFile
(
String
path
,
String
content
)
{
fs
.
file
(
path
)
..
createSync
(
recursive:
true
)
..
writeAsStringSync
(
content
);
}
void
_writePackages
(
)
{
_writeFile
(
'.packages'
,
'''
test:
${fs.path.join(fs.currentDirectory.path, 'lib')}
/
'''
);
}
void
_writePubspec
(
)
{
_writeFile
(
'pubspec.yaml'
,
'''
name: test
dependencies:
flutter:
sdk: flutter
'''
);
}
Future
<
void
>
_getPackages
()
async
{
final
List
<
String
>
command
=
<
String
>[
fs
.
path
.
join
(
getFlutterRoot
(),
'bin'
,
'flutter'
),
'packages'
,
'get'
];
final
Process
process
=
await
processManager
.
start
(
command
);
final
StringBuffer
errorOutput
=
new
StringBuffer
();
process
.
stderr
.
transform
(
utf8
.
decoder
).
listen
(
errorOutput
.
write
);
final
int
exitCode
=
await
process
.
exitCode
;
if
(
exitCode
!=
0
)
throw
new
Exception
(
'flutter packages get failed:
${errorOutput.toString()}
'
);
}
packages/flutter_tools/test/integration/util.dart
0 → 100644
View file @
3456dc62
// Copyright 2018 The Chromium Authors. 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
'dart:convert'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/process_manager.dart'
;
import
'../src/common.dart'
;
void
writeFile
(
String
path
,
String
content
)
{
fs
.
file
(
path
)
..
createSync
(
recursive:
true
)
..
writeAsStringSync
(
content
);
}
void
writePackages
(
String
folder
)
{
writeFile
(
fs
.
path
.
join
(
folder
,
'.packages'
),
'''
test:
${fs.path.join(fs.currentDirectory.path, 'lib')}
/
'''
);
}
void
writePubspec
(
String
folder
)
{
writeFile
(
fs
.
path
.
join
(
folder
,
'pubspec.yaml'
),
'''
name: test
dependencies:
flutter:
sdk: flutter
'''
);
}
Future
<
void
>
getPackages
(
String
folder
)
async
{
final
List
<
String
>
command
=
<
String
>[
fs
.
path
.
join
(
getFlutterRoot
(),
'bin'
,
'flutter'
),
'packages'
,
'get'
];
final
Process
process
=
await
processManager
.
start
(
command
,
workingDirectory:
folder
);
final
StringBuffer
errorOutput
=
new
StringBuffer
();
process
.
stderr
.
transform
(
utf8
.
decoder
).
listen
(
errorOutput
.
write
);
final
int
exitCode
=
await
process
.
exitCode
;
if
(
exitCode
!=
0
)
throw
new
Exception
(
'flutter packages get failed:
${errorOutput.toString()}
'
);
}
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