mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
More verification on flutter build web, add tests and cleanup (#34090)
This commit is contained in:
parent
3c5a4dc7b2
commit
354ce1aa5a
@ -57,6 +57,9 @@ class ApplicationPackageFactory {
|
|||||||
? MacOSApp.fromMacOSProject(FlutterProject.current().macos)
|
? MacOSApp.fromMacOSProject(FlutterProject.current().macos)
|
||||||
: MacOSApp.fromPrebuiltApp(applicationBinary);
|
: MacOSApp.fromPrebuiltApp(applicationBinary);
|
||||||
case TargetPlatform.web_javascript:
|
case TargetPlatform.web_javascript:
|
||||||
|
if (!FlutterProject.current().web.existsSync()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return WebApplicationPackage(FlutterProject.current());
|
return WebApplicationPackage(FlutterProject.current());
|
||||||
case TargetPlatform.linux_x64:
|
case TargetPlatform.linux_x64:
|
||||||
return applicationBinary == null
|
return applicationBinary == null
|
||||||
|
@ -580,11 +580,14 @@ class WebProject {
|
|||||||
|
|
||||||
/// Whether this flutter project has a web sub-project.
|
/// Whether this flutter project has a web sub-project.
|
||||||
bool existsSync() {
|
bool existsSync() {
|
||||||
return parent.directory.childDirectory('web').existsSync();
|
return parent.directory.childDirectory('web').existsSync()
|
||||||
|
&& indexFile.existsSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The html file used to host the flutter web application.
|
/// The html file used to host the flutter web application.
|
||||||
File get indexFile => parent.directory.childDirectory('web').childFile('index.html');
|
File get indexFile => parent.directory
|
||||||
|
.childDirectory('web')
|
||||||
|
.childFile('index.html');
|
||||||
|
|
||||||
Future<void> ensureReadyForPlatformSpecificTooling() async {}
|
Future<void> ensureReadyForPlatformSpecificTooling() async {}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import 'dart:async';
|
|||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
|
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
|
||||||
|
|
||||||
|
import 'application_package.dart';
|
||||||
import 'asset.dart';
|
import 'asset.dart';
|
||||||
import 'base/common.dart';
|
import 'base/common.dart';
|
||||||
import 'base/file_system.dart';
|
import 'base/file_system.dart';
|
||||||
@ -112,7 +113,14 @@ class ResidentWebRunner extends ResidentRunner {
|
|||||||
String route,
|
String route,
|
||||||
bool shouldBuild = true,
|
bool shouldBuild = true,
|
||||||
}) async {
|
}) async {
|
||||||
final FlutterProject currentProject = FlutterProject.current();
|
final ApplicationPackage package = await ApplicationPackageFactory.instance.getPackageForPlatform(
|
||||||
|
TargetPlatform.web_javascript,
|
||||||
|
applicationBinary: null,
|
||||||
|
);
|
||||||
|
if (package == null) {
|
||||||
|
printError('No application found for TargetPlatform.web_javascript');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (!fs.isFileSync(mainPath)) {
|
if (!fs.isFileSync(mainPath)) {
|
||||||
String message = 'Tried to run $mainPath, but that file does not exist.';
|
String message = 'Tried to run $mainPath, but that file does not exist.';
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
@ -124,7 +132,7 @@ class ResidentWebRunner extends ResidentRunner {
|
|||||||
}
|
}
|
||||||
// Start the web compiler and build the assets.
|
// Start the web compiler and build the assets.
|
||||||
await webCompilationProxy.initialize(
|
await webCompilationProxy.initialize(
|
||||||
projectDirectory: currentProject.directory,
|
projectDirectory: FlutterProject.current().directory,
|
||||||
targets: <String>[target],
|
targets: <String>[target],
|
||||||
);
|
);
|
||||||
_lastCompiled = DateTime.now();
|
_lastCompiled = DateTime.now();
|
||||||
|
@ -19,6 +19,9 @@ import '../usage.dart';
|
|||||||
WebCompilationProxy get webCompilationProxy => context.get<WebCompilationProxy>();
|
WebCompilationProxy get webCompilationProxy => context.get<WebCompilationProxy>();
|
||||||
|
|
||||||
Future<void> buildWeb(FlutterProject flutterProject, String target, BuildInfo buildInfo) async {
|
Future<void> buildWeb(FlutterProject flutterProject, String target, BuildInfo buildInfo) async {
|
||||||
|
if (!flutterProject.web.existsSync()) {
|
||||||
|
throwToolExit('Missing index.html.');
|
||||||
|
}
|
||||||
final Status status = logger.startProgress('Compiling $target for the Web...', timeout: null);
|
final Status status = logger.startProgress('Compiling $target for the Web...', timeout: null);
|
||||||
final Stopwatch sw = Stopwatch()..start();
|
final Stopwatch sw = Stopwatch()..start();
|
||||||
final Directory outputDir = fs.directory(getWebBuildDirectory())
|
final Directory outputDir = fs.directory(getWebBuildDirectory())
|
||||||
|
@ -19,23 +19,32 @@ import '../src/context.dart';
|
|||||||
import '../src/mocks.dart';
|
import '../src/mocks.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
Cache.disableLocking();
|
MockProcessManager mockProcessManager;
|
||||||
final MockProcessManager mockProcessManager = MockProcessManager();
|
MockProcess mockProcess;
|
||||||
final MockProcess mockProcess = MockProcess();
|
MockPlatform linuxPlatform;
|
||||||
final MockPlatform linuxPlatform = MockPlatform();
|
MockPlatform notLinuxPlatform;
|
||||||
final MockPlatform notLinuxPlatform = MockPlatform();
|
|
||||||
|
|
||||||
when(mockProcess.exitCode).thenAnswer((Invocation invocation) async {
|
setUpAll(() {
|
||||||
return 0;
|
Cache.disableLocking();
|
||||||
});
|
});
|
||||||
when(mockProcess.stderr).thenAnswer((Invocation invocation) {
|
|
||||||
return const Stream<List<int>>.empty();
|
setUp(() {
|
||||||
|
mockProcessManager = MockProcessManager();
|
||||||
|
mockProcess = MockProcess();
|
||||||
|
linuxPlatform = MockPlatform();
|
||||||
|
notLinuxPlatform = MockPlatform();
|
||||||
|
when(mockProcess.exitCode).thenAnswer((Invocation invocation) async {
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
when(mockProcess.stderr).thenAnswer((Invocation invocation) {
|
||||||
|
return const Stream<List<int>>.empty();
|
||||||
|
});
|
||||||
|
when(mockProcess.stdout).thenAnswer((Invocation invocation) {
|
||||||
|
return const Stream<List<int>>.empty();
|
||||||
|
});
|
||||||
|
when(linuxPlatform.isLinux).thenReturn(true);
|
||||||
|
when(notLinuxPlatform.isLinux).thenReturn(false);
|
||||||
});
|
});
|
||||||
when(mockProcess.stdout).thenAnswer((Invocation invocation) {
|
|
||||||
return const Stream<List<int>>.empty();
|
|
||||||
});
|
|
||||||
when(linuxPlatform.isLinux).thenReturn(true);
|
|
||||||
when(notLinuxPlatform.isLinux).thenReturn(false);
|
|
||||||
|
|
||||||
testUsingContext('Linux build fails when there is no linux project', () async {
|
testUsingContext('Linux build fails when there is no linux project', () async {
|
||||||
final BuildCommand command = BuildCommand();
|
final BuildCommand command = BuildCommand();
|
||||||
|
@ -19,24 +19,34 @@ import '../src/context.dart';
|
|||||||
import '../src/mocks.dart';
|
import '../src/mocks.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
Cache.disableLocking();
|
MockProcessManager mockProcessManager;
|
||||||
final MockProcessManager mockProcessManager = MockProcessManager();
|
MemoryFileSystem memoryFilesystem;
|
||||||
final MemoryFileSystem memoryFilesystem = MemoryFileSystem();
|
MockProcess mockProcess;
|
||||||
final MockProcess mockProcess = MockProcess();
|
MockPlatform macosPlatform;
|
||||||
final MockPlatform macosPlatform = MockPlatform();
|
MockPlatform notMacosPlatform;
|
||||||
final MockPlatform notMacosPlatform = MockPlatform();
|
|
||||||
|
|
||||||
when(mockProcess.exitCode).thenAnswer((Invocation invocation) async {
|
setUpAll(() {
|
||||||
|
Cache.disableLocking();
|
||||||
|
});
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
mockProcessManager = MockProcessManager();
|
||||||
|
memoryFilesystem = MemoryFileSystem();
|
||||||
|
mockProcess = MockProcess();
|
||||||
|
macosPlatform = MockPlatform();
|
||||||
|
notMacosPlatform = MockPlatform();
|
||||||
|
when(mockProcess.exitCode).thenAnswer((Invocation invocation) async {
|
||||||
return 0;
|
return 0;
|
||||||
|
});
|
||||||
|
when(mockProcess.stderr).thenAnswer((Invocation invocation) {
|
||||||
|
return const Stream<List<int>>.empty();
|
||||||
|
});
|
||||||
|
when(mockProcess.stdout).thenAnswer((Invocation invocation) {
|
||||||
|
return const Stream<List<int>>.empty();
|
||||||
|
});
|
||||||
|
when(macosPlatform.isMacOS).thenReturn(true);
|
||||||
|
when(notMacosPlatform.isMacOS).thenReturn(false);
|
||||||
});
|
});
|
||||||
when(mockProcess.stderr).thenAnswer((Invocation invocation) {
|
|
||||||
return const Stream<List<int>>.empty();
|
|
||||||
});
|
|
||||||
when(mockProcess.stdout).thenAnswer((Invocation invocation) {
|
|
||||||
return const Stream<List<int>>.empty();
|
|
||||||
});
|
|
||||||
when(macosPlatform.isMacOS).thenReturn(true);
|
|
||||||
when(notMacosPlatform.isMacOS).thenReturn(false);
|
|
||||||
|
|
||||||
testUsingContext('macOS build fails when there is no macos project', () async {
|
testUsingContext('macOS build fails when there is no macos project', () async {
|
||||||
final BuildCommand command = BuildCommand();
|
final BuildCommand command = BuildCommand();
|
||||||
|
96
packages/flutter_tools/test/commands/build_web_test.dart
Normal file
96
packages/flutter_tools/test/commands/build_web_test.dart
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2019 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 'package:flutter_tools/src/base/common.dart';
|
||||||
|
import 'package:flutter_tools/src/base/file_system.dart';
|
||||||
|
import 'package:flutter_tools/src/base/platform.dart';
|
||||||
|
import 'package:flutter_tools/src/build_info.dart';
|
||||||
|
import 'package:flutter_tools/src/cache.dart';
|
||||||
|
import 'package:flutter_tools/src/project.dart';
|
||||||
|
import 'package:flutter_tools/src/resident_runner.dart';
|
||||||
|
import 'package:flutter_tools/src/resident_web_runner.dart';
|
||||||
|
import 'package:flutter_tools/src/version.dart';
|
||||||
|
import 'package:flutter_tools/src/web/compile.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
|
||||||
|
import '../src/common.dart';
|
||||||
|
import '../src/testbed.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
MockWebCompilationProxy mockWebCompilationProxy;
|
||||||
|
Testbed testbed;
|
||||||
|
MockPlatform mockPlatform;
|
||||||
|
|
||||||
|
setUpAll(() {
|
||||||
|
Cache.disableLocking();
|
||||||
|
});
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
mockWebCompilationProxy = MockWebCompilationProxy();
|
||||||
|
testbed = Testbed(setup: () {
|
||||||
|
fs.file('pubspec.yaml')
|
||||||
|
..createSync()
|
||||||
|
..writeAsStringSync('name: foo\n');
|
||||||
|
fs.file('.packages').createSync();
|
||||||
|
fs.file(fs.path.join('web', 'index.html')).createSync(recursive: true);
|
||||||
|
fs.file(fs.path.join('lib', 'main.dart')).createSync(recursive: true);
|
||||||
|
when(mockWebCompilationProxy.initialize(
|
||||||
|
projectDirectory: anyNamed('projectDirectory'),
|
||||||
|
targets: anyNamed('targets'),
|
||||||
|
release: anyNamed('release')
|
||||||
|
)).thenAnswer((Invocation invocation) {
|
||||||
|
final String path = fs.path.join('.dart_tool', 'build', 'flutter_web', 'foo', 'lib', 'main_web_entrypoint.dart.js');
|
||||||
|
fs.file(path).createSync(recursive: true);
|
||||||
|
fs.file('$path.map').createSync();
|
||||||
|
return Future<bool>.value(true);
|
||||||
|
});
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
WebCompilationProxy: () => mockWebCompilationProxy,
|
||||||
|
Platform: () => mockPlatform,
|
||||||
|
FlutterVersion: () => MockFlutterVersion(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Refuses to build for web when missing index.html', () => testbed.run(() async {
|
||||||
|
fs.file(fs.path.join('web', 'index.html')).deleteSync();
|
||||||
|
|
||||||
|
expect(buildWeb(
|
||||||
|
FlutterProject.current(),
|
||||||
|
fs.path.join('lib', 'main.dart'),
|
||||||
|
BuildInfo.debug,
|
||||||
|
), throwsA(isInstanceOf<ToolExit>()));
|
||||||
|
}));
|
||||||
|
|
||||||
|
test('Refuses to build using runner when missing index.html', () => testbed.run(() async {
|
||||||
|
fs.file(fs.path.join('web', 'index.html')).deleteSync();
|
||||||
|
|
||||||
|
final ResidentWebRunner runner = ResidentWebRunner(
|
||||||
|
<FlutterDevice>[],
|
||||||
|
flutterProject: FlutterProject.current(),
|
||||||
|
ipv6: false,
|
||||||
|
);
|
||||||
|
expect(await runner.run(), 1);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test('Can build for web', () => testbed.run(() async {
|
||||||
|
|
||||||
|
await buildWeb(
|
||||||
|
FlutterProject.current(),
|
||||||
|
fs.path.join('lib', 'main.dart'),
|
||||||
|
BuildInfo.debug,
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockWebCompilationProxy extends Mock implements WebCompilationProxy {}
|
||||||
|
class MockPlatform extends Mock implements Platform {
|
||||||
|
@override
|
||||||
|
Map<String, String> environment = <String, String>{
|
||||||
|
'FLUTTER_ROOT': '/',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
class MockFlutterVersion extends Mock implements FlutterVersion {
|
||||||
|
@override
|
||||||
|
bool get isStable => false;
|
||||||
|
}
|
@ -19,29 +19,40 @@ import '../src/context.dart';
|
|||||||
import '../src/mocks.dart';
|
import '../src/mocks.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
Cache.disableLocking();
|
MockProcessManager mockProcessManager;
|
||||||
final MockProcessManager mockProcessManager = MockProcessManager();
|
MemoryFileSystem memoryFilesystem;
|
||||||
final MemoryFileSystem memoryFilesystem = MemoryFileSystem(style: FileSystemStyle.windows);
|
MockProcess mockProcess;
|
||||||
final MockProcess mockProcess = MockProcess();
|
MockPlatform windowsPlatform;
|
||||||
final MockPlatform windowsPlatform = MockPlatform()
|
MockPlatform notWindowsPlatform;
|
||||||
..environment['PROGRAMFILES(X86)'] = r'C:\Program Files (x86)\';
|
MockVisualStudio mockVisualStudio;
|
||||||
final MockPlatform notWindowsPlatform = MockPlatform();
|
|
||||||
final MockVisualStudio mockVisualStudio = MockVisualStudio();
|
|
||||||
const String solutionPath = r'C:\windows\Runner.sln';
|
const String solutionPath = r'C:\windows\Runner.sln';
|
||||||
const String visualStudioPath = r'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community';
|
const String visualStudioPath = r'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community';
|
||||||
const String vcvarsPath = visualStudioPath + r'\VC\Auxiliary\Build\vcvars64.bat';
|
const String vcvarsPath = visualStudioPath + r'\VC\Auxiliary\Build\vcvars64.bat';
|
||||||
|
|
||||||
when(mockProcess.exitCode).thenAnswer((Invocation invocation) async {
|
setUpAll(() {
|
||||||
return 0;
|
Cache.disableLocking();
|
||||||
});
|
});
|
||||||
when(mockProcess.stderr).thenAnswer((Invocation invocation) {
|
|
||||||
return const Stream<List<int>>.empty();
|
setUp(() {
|
||||||
|
mockProcessManager = MockProcessManager();
|
||||||
|
memoryFilesystem = MemoryFileSystem(style: FileSystemStyle.windows);
|
||||||
|
mockProcess = MockProcess();
|
||||||
|
windowsPlatform = MockPlatform()
|
||||||
|
..environment['PROGRAMFILES(X86)'] = r'C:\Program Files (x86)\';
|
||||||
|
notWindowsPlatform = MockPlatform();
|
||||||
|
mockVisualStudio = MockVisualStudio();
|
||||||
|
when(mockProcess.exitCode).thenAnswer((Invocation invocation) async {
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
when(mockProcess.stderr).thenAnswer((Invocation invocation) {
|
||||||
|
return const Stream<List<int>>.empty();
|
||||||
|
});
|
||||||
|
when(mockProcess.stdout).thenAnswer((Invocation invocation) {
|
||||||
|
return const Stream<List<int>>.empty();
|
||||||
|
});
|
||||||
|
when(windowsPlatform.isWindows).thenReturn(true);
|
||||||
|
when(notWindowsPlatform.isWindows).thenReturn(false);
|
||||||
});
|
});
|
||||||
when(mockProcess.stdout).thenAnswer((Invocation invocation) {
|
|
||||||
return const Stream<List<int>>.empty();
|
|
||||||
});
|
|
||||||
when(windowsPlatform.isWindows).thenReturn(true);
|
|
||||||
when(notWindowsPlatform.isWindows).thenReturn(false);
|
|
||||||
|
|
||||||
testUsingContext('Windows build fails when there is no vcvars64.bat', () async {
|
testUsingContext('Windows build fails when there is no vcvars64.bat', () async {
|
||||||
final BuildCommand command = BuildCommand();
|
final BuildCommand command = BuildCommand();
|
||||||
|
@ -11,6 +11,7 @@ import 'package:flutter_tools/src/base/logger.dart';
|
|||||||
import 'package:flutter_tools/src/base/terminal.dart';
|
import 'package:flutter_tools/src/base/terminal.dart';
|
||||||
import 'package:flutter_tools/src/cache.dart';
|
import 'package:flutter_tools/src/cache.dart';
|
||||||
import 'package:flutter_tools/src/context_runner.dart';
|
import 'package:flutter_tools/src/context_runner.dart';
|
||||||
|
import 'package:flutter_tools/src/usage.dart';
|
||||||
|
|
||||||
import 'context.dart';
|
import 'context.dart';
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ final Map<Type, Generator> _testbedDefaults = <Type, Generator>{
|
|||||||
FileSystem: () => MemoryFileSystem(), // Keeps tests fast by avoid actual file system.
|
FileSystem: () => MemoryFileSystem(), // Keeps tests fast by avoid actual file system.
|
||||||
Logger: () => BufferLogger(), // Allows reading logs and prevents stdout.
|
Logger: () => BufferLogger(), // Allows reading logs and prevents stdout.
|
||||||
OutputPreferences: () => OutputPreferences(showColor: false), // configures BufferLogger to avoid color codes.
|
OutputPreferences: () => OutputPreferences(showColor: false), // configures BufferLogger to avoid color codes.
|
||||||
|
Usage: () => NoOpUsage(), // prevent addition of analytics from burdening test mocks
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Manages interaction with the tool injection and runner system.
|
/// Manages interaction with the tool injection and runner system.
|
||||||
@ -60,7 +62,7 @@ class Testbed {
|
|||||||
/// `overrides` provides more overrides in addition to the test defaults.
|
/// `overrides` provides more overrides in addition to the test defaults.
|
||||||
/// `setup` may be provided to apply mocks within the tool managed zone,
|
/// `setup` may be provided to apply mocks within the tool managed zone,
|
||||||
/// including any specified overrides.
|
/// including any specified overrides.
|
||||||
Testbed({Future<void> Function() setup, Map<Type, Generator> overrides})
|
Testbed({FutureOr<void> Function() setup, Map<Type, Generator> overrides})
|
||||||
: _setup = setup,
|
: _setup = setup,
|
||||||
_overrides = overrides;
|
_overrides = overrides;
|
||||||
|
|
||||||
@ -101,3 +103,41 @@ class Testbed {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A no-op implementation of [Usage] for testing.
|
||||||
|
class NoOpUsage implements Usage {
|
||||||
|
@override
|
||||||
|
bool enabled = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool suppressAnalytics = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get clientId => 'test';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> ensureAnalyticsSent() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isFirstRun => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Map<String, Object>> get onSend => const Stream<Object>.empty();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void printWelcome() {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void sendCommand(String command, {Map<String, String> parameters}) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void sendEvent(String category, String parameter, {Map<String, String> parameters}) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void sendException(dynamic exception, StackTrace trace) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void sendTiming(String category, String variableName, Duration duration, {String label}) {}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user