diff --git a/CHANGELOG.md b/CHANGELOG.md index d5c1a46c5..988888557 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Added support for DocC Catalogs [#1091](https://github.com/yonaskolb/XcodeGen/pull/1091) @brevansio - Added support for "driver-extension" and "system-extension" product types [#1092](https://github.com/yonaskolb/XcodeGen/issues/1092) @vgorloff - Add support for conditionally linking dependencies for specific platforms [#1087](https://github.com/yonaskolb/XcodeGen/pull/1087) @daltonclaybrook +- Add ability to specify UI testing screenshot behavior in test schemes [#942](https://github.com/yonaskolb/XcodeGen/pull/942) @daltonclaybrook ### Changed - **Breaking**: Rename the `platform` field on `Dependency` to `platformFilter` [#1087](https://github.com/yonaskolb/XcodeGen/pull/1087) @daltonclaybrook diff --git a/Docs/ProjectSpec.md b/Docs/ProjectSpec.md index 4d57e3f38..91d80e3f6 100644 --- a/Docs/ProjectSpec.md +++ b/Docs/ProjectSpec.md @@ -814,6 +814,8 @@ A multiline script can be written using the various YAML multiline methods, for - [ ] **coverageTargets**: **[String]** - a list of targets to gather code coverage. Each entry can either be a simple string, or a string using [Project Reference](#project-reference) - [ ] **targets**: **[[Test Target](#test-target)]** - a list of targets to test. Each entry can either be a simple string, or a [Test Target](#test-target) - [ ] **customLLDBInit**: **String** - the absolute path to the custom `.lldbinit` file +- [ ] **captureScreenshotsAutomatically**: **Bool** - indicates whether screenshots should be captured automatically while UI Testing. This defaults to true. +- [ ] **deleteScreenshotsWhenEachTestSucceeds**: **Bool** - whether successful UI tests should cause automatically-captured screenshots to be deleted. If `captureScreenshotsAutomatically` is false, this value is ignored. This defaults to true. #### Test Target - [x] **name**: **String** - The name of the target diff --git a/Sources/ProjectSpec/Scheme.swift b/Sources/ProjectSpec/Scheme.swift index e5e30b1b0..ed921c89d 100644 --- a/Sources/ProjectSpec/Scheme.swift +++ b/Sources/ProjectSpec/Scheme.swift @@ -164,6 +164,8 @@ public struct Scheme: Equatable { public static let gatherCoverageDataDefault = false public static let disableMainThreadCheckerDefault = false public static let debugEnabledDefault = true + public static let captureScreenshotsAutomaticallyDefault = true + public static let deleteScreenshotsWhenEachTestSucceedsDefault = true public var config: String? public var gatherCoverageData: Bool @@ -178,6 +180,8 @@ public struct Scheme: Equatable { public var region: String? public var debugEnabled: Bool public var customLLDBInit: String? + public var captureScreenshotsAutomatically: Bool + public var deleteScreenshotsWhenEachTestSucceeds: Bool public struct TestTarget: Equatable, ExpressibleByStringLiteral { public static let randomExecutionOrderDefault = false @@ -236,7 +240,9 @@ public struct Scheme: Equatable { language: String? = nil, region: String? = nil, debugEnabled: Bool = debugEnabledDefault, - customLLDBInit: String? = nil + customLLDBInit: String? = nil, + captureScreenshotsAutomatically: Bool = captureScreenshotsAutomaticallyDefault, + deleteScreenshotsWhenEachTestSucceeds: Bool = deleteScreenshotsWhenEachTestSucceedsDefault ) { self.config = config self.gatherCoverageData = gatherCoverageData @@ -251,6 +257,8 @@ public struct Scheme: Equatable { self.region = region self.debugEnabled = debugEnabled self.customLLDBInit = customLLDBInit + self.captureScreenshotsAutomatically = captureScreenshotsAutomatically + self.deleteScreenshotsWhenEachTestSucceeds = deleteScreenshotsWhenEachTestSucceeds } public var shouldUseLaunchSchemeArgsEnv: Bool { @@ -475,6 +483,8 @@ extension Scheme.Test: JSONObjectConvertible { region = jsonDictionary.json(atKeyPath: "region") debugEnabled = jsonDictionary.json(atKeyPath: "debugEnabled") ?? Scheme.Test.debugEnabledDefault customLLDBInit = jsonDictionary.json(atKeyPath: "customLLDBInit") + captureScreenshotsAutomatically = jsonDictionary.json(atKeyPath: "captureScreenshotsAutomatically") ?? Scheme.Test.captureScreenshotsAutomaticallyDefault + deleteScreenshotsWhenEachTestSucceeds = jsonDictionary.json(atKeyPath: "deleteScreenshotsWhenEachTestSucceeds") ?? Scheme.Test.deleteScreenshotsWhenEachTestSucceedsDefault } } @@ -508,6 +518,14 @@ extension Scheme.Test: JSONEncodable { dict["customLLDBInit"] = customLLDBInit } + if captureScreenshotsAutomatically != Scheme.Test.captureScreenshotsAutomaticallyDefault { + dict["captureScreenshotsAutomatically"] = captureScreenshotsAutomatically + } + + if deleteScreenshotsWhenEachTestSucceeds != Scheme.Test.deleteScreenshotsWhenEachTestSucceedsDefault { + dict["deleteScreenshotsWhenEachTestSucceeds"] = deleteScreenshotsWhenEachTestSucceeds + } + return dict } } diff --git a/Sources/XcodeGenKit/SchemeGenerator.swift b/Sources/XcodeGenKit/SchemeGenerator.swift index 907e2e5d4..67f681964 100644 --- a/Sources/XcodeGenKit/SchemeGenerator.swift +++ b/Sources/XcodeGenKit/SchemeGenerator.swift @@ -228,6 +228,7 @@ public class SchemeGenerator { environmentVariables: testVariables, language: scheme.test?.language, region: scheme.test?.region, + systemAttachmentLifetime: scheme.test?.systemAttachmentLifetime, customLLDBInitFile: scheme.test?.customLLDBInit ) @@ -448,3 +449,16 @@ extension PBXProductType { } } } + +extension Scheme.Test { + var systemAttachmentLifetime: XCScheme.TestAction.AttachmentLifetime? { + switch (captureScreenshotsAutomatically, deleteScreenshotsWhenEachTestSucceeds) { + case (false, _): + return .keepNever + case (true, false): + return .keepAlways + case (true, true): + return nil + } + } +} diff --git a/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift b/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift index 16f437464..3c27b8a91 100644 --- a/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift @@ -108,6 +108,7 @@ class SchemeGeneratorTests: XCTestCase { try expect(xcscheme.launchAction?.locationScenarioReference?.identifier) == "New York, NY, USA" try expect(xcscheme.launchAction?.customLLDBInitFile) == "/sample/.lldbinit" try expect(xcscheme.testAction?.customLLDBInitFile) == "/test/.lldbinit" + try expect(xcscheme.testAction?.systemAttachmentLifetime).to.beNil() } let frameworkTarget = Scheme.BuildTarget(target: .local(framework.name), buildTypes: [.archiving]) @@ -445,6 +446,42 @@ class SchemeGeneratorTests: XCTestCase { let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) try expect(xcscheme.launchAction?.macroExpansion?.buildableName) == "MyApp.app" } + + $0.it("generates scheme capturing screenshots automatically and deleting on success") { + let xcscheme = try self.makeSnapshotScheme( + buildTarget: buildTarget, + captureScreenshotsAutomatically: true, + deleteScreenshotsWhenEachTestSucceeds: true) + + try expect(xcscheme.testAction?.systemAttachmentLifetime).to.beNil() + } + + $0.it("generates scheme capturing screenshots and not deleting") { + let xcscheme = try self.makeSnapshotScheme( + buildTarget: buildTarget, + captureScreenshotsAutomatically: true, + deleteScreenshotsWhenEachTestSucceeds: false) + + try expect(xcscheme.testAction?.systemAttachmentLifetime) == .keepAlways + } + + $0.it("generates scheme not capturing screenshots") { + let xcscheme = try self.makeSnapshotScheme( + buildTarget: buildTarget, + captureScreenshotsAutomatically: false, + deleteScreenshotsWhenEachTestSucceeds: false) + + try expect(xcscheme.testAction?.systemAttachmentLifetime) == .keepNever + } + + $0.it("ignores screenshot delete preference when not capturing screenshots") { + let xcscheme = try self.makeSnapshotScheme( + buildTarget: buildTarget, + captureScreenshotsAutomatically: false, + deleteScreenshotsWhenEachTestSucceeds: true) + + try expect(xcscheme.testAction?.systemAttachmentLifetime) == .keepNever + } } } @@ -503,4 +540,20 @@ class SchemeGeneratorTests: XCTestCase { let xcodeProject = try project.generateXcodeProject() return try unwrap(xcodeProject.sharedData?.schemes.first) } + + private func makeSnapshotScheme(buildTarget: Scheme.BuildTarget, captureScreenshotsAutomatically: Bool, deleteScreenshotsWhenEachTestSucceeds: Bool) throws -> XCScheme { + let scheme = Scheme( + name: "MyScheme", + build: Scheme.Build(targets: [buildTarget]), + run: Scheme.Run(config: "Debug"), + test: Scheme.Test(config: "Debug", captureScreenshotsAutomatically: captureScreenshotsAutomatically, deleteScreenshotsWhenEachTestSucceeds: deleteScreenshotsWhenEachTestSucceeds) + ) + let project = Project( + name: "test", + targets: [app, framework], + schemes: [scheme] + ) + let xcodeProject = try project.generateXcodeProject() + return try unwrap(xcodeProject.sharedData?.schemes.first) + } }