Skip to content

Commit 2edc5d4

Browse files
committed
Recognise "integration_test" folder as tests that require a device
See #3009.
1 parent 48b3f21 commit 2edc5d4

4 files changed

Lines changed: 68 additions & 31 deletions

File tree

‎src/debug/flutter_test_debug_impl.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ export class FlutterTestDebugSession extends DartTestDebugSession {
1919
appArgs = appArgs.concat(args.args);
2020
}
2121

22+
if (args.deviceId) {
23+
appArgs.push("-d");
24+
appArgs.push(args.deviceId);
25+
}
26+
2227
if (args.program)
2328
appArgs.push(this.sourceFileForArgs(args));
2429

‎src/extension/commands/sdk.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,7 @@ export class SdkCommands {
743743
if (!packageNameRegex.test(input))
744744
return "Flutter project names should be all lowercase, with underscores to separate words";
745745

746-
const bannedNames = ["flutter", "flutter_test", "test"];
746+
const bannedNames = ["flutter", "flutter_test", "test", "integration_test"];
747747
if (bannedNames.includes(input))
748748
return `You may not use ${input} as the name for a flutter project`;
749749

‎src/extension/providers/debug_config_provider.ts‎

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export class DebugConfigProvider implements DebugConfigurationProvider {
162162
// Some helpers for conditions below.
163163
const isAnyFlutter = debugType === DebuggerType.Flutter || debugType === DebuggerType.Web;
164164
const isStandardFlutter = debugType === DebuggerType.Flutter;
165+
const isIntegrationTest = debugConfig.program && isInsideFolderNamed(debugConfig.program as string, "integration_test");
165166
const isTest = debugConfig.program && isTestFileOrFolder(debugConfig.program as string);
166167
const argsHaveTestNameFilter = isTest && debugConfig.args && (debugConfig.args.indexOf("--name") !== -1 || debugConfig.args.indexOf("--pname") !== -1);
167168

@@ -177,14 +178,22 @@ export class DebugConfigProvider implements DebugConfigurationProvider {
177178
debugType = DebuggerType.PubTest;
178179
break;
179180
case DebuggerType.Flutter:
180-
if (!debugConfig.runTestsOnDevice || argsHaveTestNameFilter) {
181-
if (debugConfig.runTestsOnDevice && argsHaveTestNameFilter) {
182-
vs.window.showWarningMessage("Running with 'flutter test' as 'runTestsOnDevice' is not supported for individual tests.");
183-
logger.info(`runTestsOnDevice is set but args have test filter so will still use Flutter`);
184-
}
181+
if (isIntegrationTest) {
182+
// Integration tests always use "flutter test".
185183
debugType = DebuggerType.FlutterTest;
186-
} else {
184+
} else if (debugConfig.runTestsOnDevice && argsHaveTestNameFilter) {
185+
// Non-integration tests set to run on device but have a test name filter will also have
186+
// to run with "flutter test".
187+
vs.window.showWarningMessage("Running with 'flutter test' as 'runTestsOnDevice' is not supported for individual tests.");
188+
logger.info(`runTestsOnDevice is set but args have test filter so will still use Flutter`);
189+
debugType = DebuggerType.FlutterTest;
190+
} else if (debugConfig.runTestsOnDevice) {
191+
// Anything else (eg. Non-integration tests without a test name filter) is allowed to
192+
// run on a device if specified.
187193
logger.info(`runTestsOnDevice is set, so will use Flutter instead of FlutterTest`);
194+
} else {
195+
// Otherwise, default is to use "flutter test".
196+
debugType = DebuggerType.FlutterTest;
188197
}
189198
break;
190199
case DebuggerType.Web:
@@ -248,29 +257,33 @@ export class DebugConfigProvider implements DebugConfigurationProvider {
248257
if (token && token.isCancellationRequested)
249258
return;
250259

251-
let deviceToLaunchOn = this.deviceManager?.getDevice(debugConfig.deviceId) || this.deviceManager?.currentDevice;
252260

253261
// Ensure we have a device if required.
254-
if (debugType === DebuggerType.Flutter && this.deviceManager && this.daemon && debugConfig.deviceId !== "flutter-tester") {
255-
let supportedPlatforms = this.daemon.capabilities.providesPlatformTypes && debugConfig.cwd
256-
? (await this.daemon.getSupportedPlatforms(debugConfig.cwd)).platforms
257-
: [];
258-
259-
// If the current device is not valid, prompt the user.
260-
if (!this.deviceManager.isSupported(supportedPlatforms, deviceToLaunchOn))
261-
deviceToLaunchOn = await this.deviceManager.showDevicePicker(supportedPlatforms);
262-
263-
// Refresh the supported platforms, as the we may have enabled new platforms during
264-
// the call to showDevicePicker.
265-
supportedPlatforms = this.daemon.capabilities.providesPlatformTypes && debugConfig.cwd
266-
? (await this.daemon.getSupportedPlatforms(debugConfig.cwd)).platforms
267-
: [];
268-
269-
// If we still don't have a valid device, show an error.
270-
if (!this.deviceManager.isSupported(supportedPlatforms, deviceToLaunchOn)) {
271-
logger.warn("Unable to launch due to no active device");
272-
window.showInformationMessage("Cannot launch without an active device");
273-
return undefined; // undefined means silent (don't open launch.json).
262+
let deviceToLaunchOn;
263+
const requiresDevice = debugType === DebuggerType.Flutter || (DebuggerType.FlutterTest && isIntegrationTest);
264+
if (requiresDevice) {
265+
deviceToLaunchOn = this.deviceManager?.getDevice(debugConfig.deviceId) || this.deviceManager?.currentDevice;
266+
if (this.deviceManager && this.daemon && debugConfig.deviceId !== "flutter-tester") {
267+
let supportedPlatforms = this.daemon.capabilities.providesPlatformTypes && debugConfig.cwd
268+
? (await this.daemon.getSupportedPlatforms(debugConfig.cwd)).platforms
269+
: [];
270+
271+
// If the current device is not valid, prompt the user.
272+
if (!this.deviceManager.isSupported(supportedPlatforms, deviceToLaunchOn))
273+
deviceToLaunchOn = await this.deviceManager.showDevicePicker(supportedPlatforms);
274+
275+
// Refresh the supported platforms, as the we may have enabled new platforms during
276+
// the call to showDevicePicker.
277+
supportedPlatforms = this.daemon.capabilities.providesPlatformTypes && debugConfig.cwd
278+
? (await this.daemon.getSupportedPlatforms(debugConfig.cwd)).platforms
279+
: [];
280+
281+
// If we still don't have a valid device, show an error.
282+
if (!this.deviceManager.isSupported(supportedPlatforms, deviceToLaunchOn)) {
283+
logger.warn("Unable to launch due to no active device");
284+
window.showInformationMessage("Cannot launch without an active device");
285+
return undefined; // undefined means silent (don't open launch.json).
286+
}
274287
}
275288
}
276289

@@ -304,7 +317,7 @@ export class DebugConfigProvider implements DebugConfigurationProvider {
304317
const file = fsPath(fd[0]);
305318
return isWithinPath(file, debugConfig.cwd)
306319
// Ignore errors in test folder unless it's the file we're running.
307-
&& (!isInsideFolderNamed(file, "test") || file === debugConfig.program);
320+
&& ((!isInsideFolderNamed(file, "test") || !isInsideFolderNamed(file, "integration_test")) || file === debugConfig.program);
308321
});
309322
if (firstRelevantDiagnostic) {
310323
logger.warn("Project has errors, prompting user");
@@ -601,6 +614,15 @@ export class DynamicDebugConfigProvider implements DebugConfigurationProvider {
601614
type: "dart",
602615
});
603616
}
617+
if (isFlutter && exists("integration_test")) {
618+
results.push({
619+
name: `${name} (${isFlutter ? "Flutter" : "Dart"} Integration Tests)`,
620+
program: "integration_test",
621+
cwd,
622+
request: "launch",
623+
type: "dart",
624+
});
625+
}
604626
}
605627
return results;
606628
}

‎src/extension/utils.ts‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,12 @@ export function isTestFile(file: string): boolean {
123123
// https://github.com/Dart-Code/Dart-Code/issues/2021
124124
// https://github.com/Dart-Code/Dart-Code/issues/2034
125125
return !!file && isDartFile(file)
126-
&& (isInsideFolderNamed(file, "test") || isInsideFolderNamed(file, "test_driver") || config.allowTestsOutsideTestFolder)
126+
&& (
127+
isInsideFolderNamed(file, "test")
128+
|| isInsideFolderNamed(file, "integration_test")
129+
|| isInsideFolderNamed(file, "test_driver")
130+
|| config.allowTestsOutsideTestFolder
131+
)
127132
&& file.toLowerCase().endsWith("_test.dart");
128133
}
129134

@@ -134,7 +139,12 @@ export function isPubRunnableTestFile(file: string): boolean {
134139
}
135140

136141
export function isTestFolder(path: string): boolean {
137-
return !!path && isInsideFolderNamed(path, "test") && fs.existsSync(path) && fs.statSync(path).isDirectory();
142+
return !!path
143+
&& (
144+
isInsideFolderNamed(path, "test")
145+
|| isInsideFolderNamed(path, "integration_test")
146+
) && fs.existsSync(path)
147+
&& fs.statSync(path).isDirectory();
138148
}
139149

140150
export function projectShouldUsePubForTests(folder: string, config: WorkspaceConfig): boolean {

0 commit comments

Comments
 (0)