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:
Daniel Jankowski 2021-06-19 21:13:50 +02:00 committed by GitHub
parent 71b0bf3792
commit 35fa0d1224
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 154 additions and 18 deletions

View File

@ -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

View File

@ -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, [])
}
}

View File

@ -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
)
}
}

View File

@ -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()
)

View File

@ -22,6 +22,7 @@ final class AutomationGraphMapperProvider: GraphMapperProviding {
mappers.append(
TestsCacheGraphMapper(hashesCacheDirectory: testsCacheDirectory, config: config)
)
mappers.append(CacheTreeShakingGraphMapper())
return SequentialGraphMapper(mappers)
}
}

View File

@ -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)
}
}

View File

@ -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)
)
)
}

View File

@ -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(

View File

@ -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)
}
}

View File

@ -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()
}
}

View File

@ -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
)
}
}

View File

@ -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
)
}
}

View File

@ -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 |