fastlane-old / snapshot

Automate taking localized screenshots of your iOS app on every device
https://fastlane.tools
1.95k stars 140 forks source link

Dynamic Target Application #348

Closed klevison closed 8 years ago

klevison commented 8 years ago

For any reasons I have 3 targets/scheme each one to load a different theme. So, when I run snapshot command it only take the snapshot of the target selected into Target Application (UITest Target).

Target

Is there a way to deal with it dynamically? I wanna run snapshot command and get the result of 3 themes/targets/scheme.

KrauseFx commented 8 years ago

By default snapshot will print out a list of available schemes. I think it's only possible to do that for schemes.

klevison commented 8 years ago

My solution:

1) Create 3 UITest targets

screen shot 2015-12-10 at 1 42 54 pm

2) Set the test action foreach

screen shot 2015-12-10 at 1 43 36 pm

3) Create

screen shot 2015-12-10 at 1 43 09 pm

3.1 Create SnapshotUITests.swift targeting to all UITest targets (step 1).

import XCTest

class SnapshotUITests: XCTestCase {

    override func setUp() {
        super.setUp()

        continueAfterFailure = false
        let app = XCUIApplication()
        setupSnapshot(app)
        app.launch()
    }

    override func tearDown() {
        super.tearDown()
    }

    func testMainScreenSnapShot() {
        snapshot("01MainScrenn")
    }

    func testLeftMenuSnapShot() {
        XCUIApplication().navigationBars["App"].buttons["menu"].tap()
        snapshot("02LeftMenu")
    }

}

3.2 Create SnapshotPrimeUITests file where it targets to SnapshotPrimeUITests target

class SnapshotPrimeUITests: SnapshotUITests {

}

3.2 Create SnapshotExclusiveUITests file where it targets to SnapshotExclusiveUITests target

class SnapshotExclusiveUITests: SnapshotUITests {

}

3.3 Create SnapshotClassicUITests file where it targets to SnapshotClassicUITests target

class SnapshotClassicUITests: SnapshotUITests {

}

4.1) Snapfile

scheme ENV["SCHEME"]

devices([
   "iPhone 6s",
   "iPhone 6s Plus",
   "iPhone 5s",
   "iPhone 4s"
])

languages([
  "pt-BR"
])

launch_arguments(ENV["SCHEME"])

4.2) Fastfile

desc "Runs all the tests"
  ["Prime", "Exclusive", "Classic"].each do |scheme_name|
    ENV["SCHEME"] = scheme_name
    snapshot
  end

Result:

screen shot 2015-12-10 at 7 58 50 pm
klevison commented 8 years ago

With this solution I have the "ideal final result" but I'm looking for a way that avoid create a lot of targets and subclass..

KrauseFx commented 8 years ago

@klevison Thanks for sharing. Do you know if there is a way to only run a subset of tests using xcodebuild? If so, I can easily add this to snapshot.

hebertialmeida commented 8 years ago

@KrauseFx I know that xctool can do this https://github.com/facebook/xctool#testing

Also, there is a Open Radar on this http://www.openradar.me/15750338

KrauseFx commented 8 years ago

@hebertialmeida I might be wrong, but I think xctool doesn't use xcodebuild to run tests.

iOSAppMaker commented 8 years ago

Same issue. Multiple targets.

iOSAppMaker commented 8 years ago

Is there any progress on this??

HughJeffner commented 8 years ago

I have over 70 targets (don't ask) and a single ui test could cover them all so I want to avoid creating 70+ additional targets for the unit tests.

owurman commented 8 years ago

I also have the same problem (50+ targets, all with minor differences for particular clients, that otherwise need the same UI test). The OP here makes a decent architectural suggestion to at least not have to copy+paste the test every time, but if anyone else has a better way of implementing it, I'm happy to try to add it. Right now I don't know if it's possible to dynamically specify the "Target Application" for a UI Test... that would seem to be easiest for me. I'll look and see if there's some magic voodoo for this but if you've figured out a way (without unsafe changes to the pbxproj file) please share!

owurman commented 8 years ago

@KrauseFx I'm not seeing how it would help to be able to run a subset of tests... one would still need to create a separate Test for each Target Application. What we really need is a way to dynamically set Target Application and the only way I'm coming up with is copying the .pbxproj and doing a manual edit to set the desired Target Application, which would be rather fragile. I've filed another bug against Apple but given my track record of not even getting responses lately, I'm not holding my breath.

owurman commented 8 years ago

For those who are interested in this, I managed to make this work dynamically using some hackery and Xcodeproj. I'm not going to do a pull request (yet) because it's just too hacky. But in general, I set up a single UI test and set up every Scheme to build/test it. Then I have this in my Fastfile:

Note that my setup has fastlane set up for each target under a "Custom//" subdirectory, hence the "../". Also, I had to hack /Library/Ruby/Gems/2.0.0/gems/snapshot-1.9.0/lib/snapshot/detect_values.rb to comment out line 8 ("config.load_configuration_file(Snapshot.snapfile_name)") since it was failing in my configuration... there's another bug here that I'll try to fix properly (basically it tries running in the fastlane directory as pwd, then whether or not it succeeds it tries going up the directory structure, so when sourcing another file like I am it inevitably fails in one or the other pwd because the file is not found).

   lane :snapshot do
     prepare_UITest_target("../../../MyRealApp.xcodeproj", "../../../test.xcodeproj", ENV["SCHEME"])
     snapshot(clean: true, project: "../../test.xcodeproj", scheme:ENV["SCHEME"])
   end
    def prepare_UITest_target(source, dest, test_target)
      # Make a copy and open it so we can't harm the actual project file
      FileUtils::cp_r(source + "/.", dest)
      project = Xcodeproj::Project.open(source)

      # Find the target for the test
      dependency_target = 0
      project.targets.each do |target|
        if test_target == target.name
          dependency_target = target
        end
      end

      # Add the target as a dependency and update the TEST_TARGET_NAME's
      project.targets.each do |target|
        # HACK ALERT: Hardcoded UI Test target name... have not yet generalized
        next unless "SnapshotUITestsCustom" == target.name
        target.add_dependency(dependency_target)
        target.build_configurations.each do |configuration|
          configuration.build_settings['TEST_TARGET_NAME'] = test_target
        end
      end

      project.save(dest)
      # Change all references to test.xcodeproj -- XXX: This is not generic
      # HACK ALERT: Hardcoded the source and dest project names
      system("LC_ALL=C find #{dest} -type f -exec sed -i '' 's/MyRealApp.xcodeproj/test.xcodeproj/g' '{}' \\;")

    end

I apologize for not having cleaned it up, but I got it working and wanted to document ASAP. I'll edit this if I'm able to get it properly generalized (and un-hacked enough to support a pull request to build it in to snapshot)

The biggest thing I'd like to do is make the copy in the fastlane/ directory, but then it won't build because it's missing all of the files. I might be able to hack this again with sed to fix the relative path, but that seems even worse. I'm open to suggestions for improvement.

fastlane-bot commented 8 years ago

This issue was migrated to https://github.com/fastlane/fastlane/issues/1676. Please post all further comments there.

fastlane is now a mono repo, you can read more about the change in our blog post. All tools are now available in the fastlane main repo :rocket: