Add --skip-ui-tests parameter to tuist test command (#2832)
* Add --skip-ui-tests parameter to tuist test command * Add changelog entry * Fix formatting * Add unit tests target in tests * Rename PruneUITestsProjectMapperTests to SkipUITestsProjectMapperTests * Rename skipUiTests to skipUITests * Restore Package.resolved * Update documentation * Get rid of short for skip ui tests flag and update the docs
This commit is contained in:
parent
71b0bf3792
commit
35fa0d1224
|
@ -8,6 +8,7 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
|
|||
|
||||
- Add `tvTopShelfExtension` and `tvIntentsExtension` target product. [#2793](https://github.com/tuist/tuist/pull/2793) by [@rmnblm](https://github.com/rmnblm)
|
||||
- The `tuist dependencies` command generates a `graph.json` file for the `Carthage` dependencies. [#3043](https://github.com/tuist/tuist/pull/3043) by [@laxmorek](https://github.com/laxmorek)
|
||||
- Add --skip-ui-tests parameter to tuist test command [#2832](https://github.com/tuist/tuist/pull/2832) by [@mollyIV](https://github.com/mollyIV).
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import Foundation
|
||||
import TSCBasic
|
||||
import TuistCore
|
||||
import TuistGraph
|
||||
|
||||
public final class SkipUITestsProjectMapper: ProjectMapping {
|
||||
public init() {}
|
||||
|
||||
public func map(project: Project) throws -> (Project, [SideEffectDescriptor]) {
|
||||
var project = project
|
||||
project.targets = project.targets.map { target in
|
||||
var copy = target
|
||||
if copy.product == .uiTests {
|
||||
copy.prune = true
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
return (project, [])
|
||||
}
|
||||
}
|
|
@ -46,6 +46,12 @@ struct TestCommand: ParsableCommand {
|
|||
)
|
||||
var configuration: String?
|
||||
|
||||
@Flag(
|
||||
name: .long,
|
||||
help: "When passed, it skips testing UI Tests targets."
|
||||
)
|
||||
var skipUITests: Bool = false
|
||||
|
||||
func run() throws {
|
||||
let absolutePath: AbsolutePath
|
||||
|
||||
|
@ -61,7 +67,8 @@ struct TestCommand: ParsableCommand {
|
|||
configuration: configuration,
|
||||
path: absolutePath,
|
||||
deviceName: device,
|
||||
osVersion: os
|
||||
osVersion: os,
|
||||
skipUITests: skipUITests
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,22 +8,25 @@ import TuistSupport
|
|||
protocol TestServiceGeneratorFactorying {
|
||||
func generator(
|
||||
automationPath: AbsolutePath,
|
||||
testsCacheDirectory: AbsolutePath
|
||||
testsCacheDirectory: AbsolutePath,
|
||||
skipUITests: Bool
|
||||
) -> Generating
|
||||
}
|
||||
|
||||
final class TestServiceGeneratorFactory: TestServiceGeneratorFactorying {
|
||||
func generator(
|
||||
automationPath: AbsolutePath,
|
||||
testsCacheDirectory: AbsolutePath
|
||||
testsCacheDirectory: AbsolutePath,
|
||||
skipUITests: Bool
|
||||
) -> Generating {
|
||||
Generator(
|
||||
projectMapperProvider: AutomationProjectMapperProvider(),
|
||||
projectMapperProvider: AutomationProjectMapperProvider(skipUITests: skipUITests),
|
||||
graphMapperProvider: AutomationGraphMapperProvider(
|
||||
testsCacheDirectory: testsCacheDirectory
|
||||
),
|
||||
workspaceMapperProvider: AutomationWorkspaceMapperProvider(
|
||||
workspaceDirectory: FileHandler.shared.resolveSymlinks(automationPath)
|
||||
workspaceDirectory: FileHandler.shared.resolveSymlinks(automationPath),
|
||||
skipUITests: skipUITests
|
||||
),
|
||||
manifestLoaderFactory: ManifestLoaderFactory()
|
||||
)
|
||||
|
|
|
@ -22,6 +22,7 @@ final class AutomationGraphMapperProvider: GraphMapperProviding {
|
|||
mappers.append(
|
||||
TestsCacheGraphMapper(hashesCacheDirectory: testsCacheDirectory, config: config)
|
||||
)
|
||||
mappers.append(CacheTreeShakingGraphMapper())
|
||||
return SequentialGraphMapper(mappers)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,14 @@ import TuistSupport
|
|||
/// It uses default `ProjectMapperProvider` but adds its own on top
|
||||
final class AutomationProjectMapperProvider: ProjectMapperProviding {
|
||||
private let projectMapperProvider: ProjectMapperProviding
|
||||
private let skipUITests: Bool
|
||||
|
||||
init(
|
||||
projectMapperProvider: ProjectMapperProviding = ProjectMapperProvider()
|
||||
projectMapperProvider: ProjectMapperProviding = ProjectMapperProvider(),
|
||||
skipUITests: Bool
|
||||
) {
|
||||
self.projectMapperProvider = projectMapperProvider
|
||||
self.skipUITests = skipUITests
|
||||
}
|
||||
|
||||
func mapper(config: Config) -> ProjectMapping {
|
||||
|
@ -37,6 +40,12 @@ final class AutomationProjectMapperProvider: ProjectMapperProviding {
|
|||
SourceRootPathProjectMapper()
|
||||
)
|
||||
|
||||
if skipUITests {
|
||||
mappers.append(
|
||||
SkipUITestsProjectMapper()
|
||||
)
|
||||
}
|
||||
|
||||
return SequentialProjectMapper(mappers: mappers)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,12 +12,13 @@ final class AutomationWorkspaceMapperProvider: WorkspaceMapperProviding {
|
|||
private let workspaceMapperProvider: WorkspaceMapperProviding
|
||||
|
||||
convenience init(
|
||||
workspaceDirectory: AbsolutePath
|
||||
workspaceDirectory: AbsolutePath,
|
||||
skipUITests: Bool
|
||||
) {
|
||||
self.init(
|
||||
workspaceDirectory: workspaceDirectory,
|
||||
workspaceMapperProvider: WorkspaceMapperProvider(
|
||||
projectMapperProvider: AutomationProjectMapperProvider()
|
||||
projectMapperProvider: AutomationProjectMapperProvider(skipUITests: skipUITests)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -76,7 +76,8 @@ final class TestService {
|
|||
configuration: String?,
|
||||
path: AbsolutePath,
|
||||
deviceName: String?,
|
||||
osVersion: String?
|
||||
osVersion: String?,
|
||||
skipUITests: Bool
|
||||
) throws {
|
||||
// Load config
|
||||
let manifestLoaderFactory = ManifestLoaderFactory()
|
||||
|
@ -93,7 +94,8 @@ final class TestService {
|
|||
|
||||
let generator = testServiceGeneratorFactory.generator(
|
||||
automationPath: Environment.shared.automationPath ?? projectDirectory,
|
||||
testsCacheDirectory: testsCacheTemporaryDirectory.path
|
||||
testsCacheDirectory: testsCacheTemporaryDirectory.path,
|
||||
skipUITests: skipUITests
|
||||
)
|
||||
logger.notice("Generating project for testing", metadata: .section)
|
||||
let graph = try generator.generateWithGraph(
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import Foundation
|
||||
import TSCBasic
|
||||
import TuistCore
|
||||
import TuistGraph
|
||||
import TuistSupport
|
||||
import XCTest
|
||||
|
||||
@testable import TuistAutomation
|
||||
@testable import TuistCoreTesting
|
||||
@testable import TuistSupportTesting
|
||||
|
||||
final class SkipUITestsProjectMapperTests: TuistUnitTestCase {
|
||||
private var subject: SkipUITestsProjectMapper!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
subject = .init()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
subject = nil
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func test_prune_is_set_to_ui_targets() throws {
|
||||
// Given
|
||||
let project = Project.test(
|
||||
targets: [
|
||||
.test(name: "App", product: .app),
|
||||
.test(name: "UnitTests", product: .unitTests),
|
||||
.test(name: "UITests", product: .uiTests),
|
||||
]
|
||||
)
|
||||
|
||||
// When
|
||||
let (gotProject, gotSideEffects) = try subject.map(project: project)
|
||||
XCTAssertEqual(
|
||||
gotProject,
|
||||
Project.test(
|
||||
targets: [
|
||||
.test(name: "App", product: .app),
|
||||
.test(name: "UnitTests", product: .unitTests),
|
||||
.test(name: "UITests", product: .uiTests, prune: true),
|
||||
]
|
||||
)
|
||||
)
|
||||
XCTAssertEmpty(gotSideEffects)
|
||||
}
|
||||
}
|
|
@ -4,11 +4,12 @@ import TSCBasic
|
|||
@testable import TuistKit
|
||||
|
||||
final class MockTestServiceGeneratorFactory: TestServiceGeneratorFactorying {
|
||||
var generatorStub: ((AbsolutePath, AbsolutePath) -> Generating)?
|
||||
var generatorStub: ((AbsolutePath, AbsolutePath, Bool) -> Generating)?
|
||||
func generator(
|
||||
automationPath: AbsolutePath,
|
||||
testsCacheDirectory: AbsolutePath
|
||||
testsCacheDirectory: AbsolutePath,
|
||||
skipUITests: Bool
|
||||
) -> Generating {
|
||||
generatorStub?(automationPath, testsCacheDirectory) ?? MockGenerator()
|
||||
generatorStub?(automationPath, testsCacheDirectory, skipUITests) ?? MockGenerator()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,8 @@ final class AutomationProjectMapperProviderTests: TuistUnitTestCase {
|
|||
contentHasher = .init()
|
||||
projectMapperProvider = .init()
|
||||
subject = AutomationProjectMapperProvider(
|
||||
projectMapperProvider: projectMapperProvider
|
||||
projectMapperProvider: projectMapperProvider,
|
||||
skipUITests: false
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -52,6 +53,10 @@ final class AutomationProjectMapperProviderTests: TuistUnitTestCase {
|
|||
sequentialProjectMapper.mappers.filter { $0 is SourceRootPathProjectMapper }.count,
|
||||
1
|
||||
)
|
||||
XCTAssertEqual(
|
||||
sequentialProjectMapper.mappers.filter { $0 is SkipUITestsProjectMapper }.count,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
func test_map() throws {
|
||||
|
@ -70,5 +75,38 @@ final class AutomationProjectMapperProviderTests: TuistUnitTestCase {
|
|||
sequentialProjectMapper.mappers.filter { $0 is SourceRootPathProjectMapper }.count,
|
||||
1
|
||||
)
|
||||
XCTAssertEqual(
|
||||
sequentialProjectMapper.mappers.filter { $0 is SkipUITestsProjectMapper }.count,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
func test_map_when_skipUITests() throws {
|
||||
// Given
|
||||
subject = AutomationProjectMapperProvider(
|
||||
projectMapperProvider: projectMapperProvider,
|
||||
skipUITests: true
|
||||
)
|
||||
|
||||
// When
|
||||
let got = subject.mapper(
|
||||
config: Config.test()
|
||||
)
|
||||
|
||||
// Then
|
||||
let sequentialProjectMapper = try XCTUnwrap(got as? SequentialProjectMapper)
|
||||
XCTAssertEqual(
|
||||
sequentialProjectMapper.mappers
|
||||
.filter { $0 is AutogeneratedSchemesProjectMapper }.count,
|
||||
0
|
||||
)
|
||||
XCTAssertEqual(
|
||||
sequentialProjectMapper.mappers.filter { $0 is SourceRootPathProjectMapper }.count,
|
||||
1
|
||||
)
|
||||
XCTAssertEqual(
|
||||
sequentialProjectMapper.mappers.filter { $0 is SkipUITestsProjectMapper }.count,
|
||||
1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ final class TestServiceTests: TuistUnitTestCase {
|
|||
contentHasher = .init()
|
||||
testsCacheTemporaryDirectory = try TemporaryDirectory(removeTreeOnDeinit: true)
|
||||
testServiceGeneratorFactory = .init()
|
||||
testServiceGeneratorFactory.generatorStub = { _, _ in
|
||||
testServiceGeneratorFactory.generatorStub = { _, _, _ in
|
||||
self.generator
|
||||
}
|
||||
let mockCacheDirectoriesProvider = try MockCacheDirectoriesProvider()
|
||||
|
@ -70,7 +70,7 @@ final class TestServiceTests: TuistUnitTestCase {
|
|||
// Given
|
||||
var automationPath: AbsolutePath?
|
||||
|
||||
testServiceGeneratorFactory.generatorStub = { gotAutomationPath, _ in
|
||||
testServiceGeneratorFactory.generatorStub = { gotAutomationPath, _, _ in
|
||||
automationPath = gotAutomationPath
|
||||
return self.generator
|
||||
}
|
||||
|
@ -265,7 +265,8 @@ private extension TestService {
|
|||
configuration: String? = nil,
|
||||
path: AbsolutePath,
|
||||
deviceName: String? = nil,
|
||||
osVersion: String? = nil
|
||||
osVersion: String? = nil,
|
||||
skipUiTests: Bool = false
|
||||
) throws {
|
||||
try run(
|
||||
schemeName: schemeName,
|
||||
|
@ -273,7 +274,8 @@ private extension TestService {
|
|||
configuration: configuration,
|
||||
path: path,
|
||||
deviceName: deviceName,
|
||||
osVersion: osVersion
|
||||
osVersion: osVersion,
|
||||
skipUITests: skipUiTests
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,3 +57,4 @@ One of the benefits of using Tuist over other automation tools is that developer
|
|||
| `--device` | `-d` | `Test on a specific device.` | | No |
|
||||
| `--os` | `-o` | `Test with a specific version of the OS.` | | No |
|
||||
| `--configuration` | `-C` | `The configuration to be used when building the scheme.` | | No |
|
||||
| `--skip-ui-tests` | n/a | `When passed, it skips testing UI Tests targets.` | False | No |
|
||||
|
|
Loading…
Reference in New Issue