This is a swift question.
I have a question on getting the placeholder (or id, etc.) from a line XCUIApplication().someView.searchField.element.
I need to achieve this in order to get the text attributes of the elements that are tap()-ed in a test code.
Below is the exact code, gotten from the https://github.com/BalestraPatrick/Tweetometer/blob/a11c20244a37eacd4a36586f679f3ba184c66f86/Carthage/Checkouts/IGListKit/Examples/Examples-iOS/IGListKitExamples-UITests/SearchViewControllerUITests.swift.
import XCTest
final class SearchViewControllerUITests: UITestCase {
var collectionViews: XCUIElementQuery!
...
func test_whenSearchingForText_thatResultsGetFiltered() {
let searchField = collectionViews.searchFields.element <- ex) this element's placeholder.
searchField.tap()
searchField.typeText("tac")
let tacos = collectionViews.cells.staticTexts["tacos"]
let small = collectionViews.cells.staticTexts["small"]
XCTAssertTrue(tacos.exists)
XCTAssertFalse(small.exists)
}
}
The full code is available in the above link, but I am very new to Swift, so that I have no idea where to find the view and the element's site of declaration (something like .xml in android code?)
Actually, I am curious if this is possible in a static way (i.e. only looking at the code, not really exploring through the GUI).
Thanks in advance for any kind of hint!
Related
Can anyone explain me why when i declare variable like this:
private let viewModel = TermsAndConditionViewModel()
// TermsAndConditionViewModel
class TermsAndConditionViewModel {
private let permissionsModel: PermissionsModel
private let userSession: UserSessionManager
init(
permissionsModel: PermissionsModel = PermissionsModelImpl(),
userSession: UserSessionManager = UserSessionManager.shared
) {
self.permissionsModel = permissionsModel
self.userSession = userSession
}
}
and run test in Xcode I got warning like
update: there is no message about warning.
and this is when I check in Xcode/Coverage
Thank for your help.
Hi #user2629744 welcome to StackOverflow.
The red bar you are seeing in the right gutter is not a warning but Xcode's Code Coverage Annotation.
It's red and it shows a 0 because there is no test exercising that code path.
It's hard to be sure without having access to your codebase, but since we're talking about a view model in your example I'm guessing that line of code comes from the view layer. Right?
If that's the case, it might be okay if you don't test it. If all the business logic lives in the view model (which you can throughly test) and you keep your view layer humble, then you'll still have the majority of your behavior covered.
Xcode 8 and Swift 3 made me really sad today :(
Please have a look and tell me if you ever had something like this and if it's possible to fix it. I've been trying different solutions, among them:
Cmd + Shift + K
Cmd + Shift + Option + K
Delete Derived Data
Change used struct (it's a nested struct in my code), flattened it, change to really basic one
Update 1:
Here's the code (although I think it's not necessarily a problem related to my implementation), it's in my tests target:
let viewModelStub: Quiz.NewRoundDetails.ViewModel = Quiz.NewRoundDetails.ViewModel(roundNumber: "", score: "", proposedAnswerParts: [
Quiz.NewRoundDetails.ViewModel.AnswersForComponent(answers: []),
Quiz.NewRoundDetails.ViewModel.AnswersForComponent(answers: []),
Quiz.NewRoundDetails.ViewModel.AnswersForComponent(answers: [])])
_ = viewController.view
viewController.display(roundModel: viewModelStub)
Here are structs:
struct Quiz {
struct NewRoundDetails {
struct Response {
let roundNumber: Int
let score: Int
}
struct ViewModel {
let roundNumber: String
let score: String
let proposedAnswerParts: [Quiz.NewRoundDetails.ViewModel.AnswersForComponent]
struct AnswersForComponent {
let answers: [String]
}
}
}
}
And in viewController things look like this:
func display(roundModel: Quiz.NewRoundDetails.ViewModel) {
...
}
Nothing so unusual I think. I have just discovered one more thing - the code works fine on the app target side, it doesn't work on tests target.
I don't have more ideas atm... Can you help me? I have created radar as well
Check this answer: Stack Overflow
It's probably an issue with targeting. If you're using the #testable key word on the top of your test file and your main project files also target your tests then the tests are referring to two different files. So your files should only target either the tests (if they're a test file) or the main project. If they have both checked uncheck one and use the #testable import [your project's name] at the top of your test file.
Ok, I got it...
I've imported my app's module with #testable and also I've had added my .swift file with model classes to the test target. Probably <MyTestModule>. Quiz.NewRoundDetails.ViewModel have been created instead of <MyAppModule>. Quiz.NewRoundDetails.ViewModel
I've been reading up on ReactiveCocoa v3 lately and I'm struggling with just setting up basic stuff. I've already read the changelog, the tests, the few SO questions and the articles by Colin Eberhardt on the subject. However, I'm still missing examples on basic bindings.
Let's say I have an app that presents the menu of the day. The app is using RAC3 and the MVVM pattern.
Model (Menu)
The model has one simple method for fetching todays menu. As for now, this don't do any network requests, it basically just creates a model object. The mainCourse property is a String.
class func fetchTodaysMenu() -> SignalProducer<Menu, NoError> {
return SignalProducer {
sink, dispoable in
let newMenu = Menu()
newMenu.mainCourse = "Some meat"
sendNext(sink, newMenu)
sendCompleted(sink)
}
}
ViewModel (MenuViewModel)
The view model exposes different String variables for letting the view controller show the menu. Let's just add one property for showing the main course.
var mainCourse = MutableProperty("")
And we add a binding for this property:
self.mainCourse <~ Menu.fetchTodaysMenu()
|> map { menu in
return menu.mainCourse!
}
ViewController (MenuViewController)
Last but not least, I want to present this main course in a view. I'll add a UILabel for this.
var headline = UILabel()
And finally I want to set the text property of that UILabel by observing my view model. Something like:
self.headline.text <~ viewModel.headline.producer
Which unfortunately does not work.
Questions
The method fetchTodaysMenu() returns a SignalProducer<Menu, NoError>, but what if I want this method to return a SignalProducer<Menu, NSError> instead? This would make my binding in my view model fail as the method now may return an error. How do I handle this?
As mentioned, the current binding in my view controller does not work. I've been playing around with creating a MutableProperty that represents the text property of the UILabel, but I never got it right. I also think it feels clumsy or verbose to have to create extra variables for each property I want to bind. This was not needed in RAC2. I intentionally also tried to avoid using DynamicProperty, but maybe I shouldn't? I basically just want to find the right way of doing RAC(self.headline, text) = RACObserve(self.viewModel, mainCourse);.
Any other feedback/guidance on how to make this basic setup is highly appreciated.
So, after writing this question Colin Eberhardt made a part 3 of his RAC3 blog post series which includes a interesting and very relevant example of using MVVM and RAC3. The post can be found here and the source code here.
Based on his work, I've managed to answer my own questions:
By taking a slightly different approach, I'm able to make the fetchTodaysMenu() return a SignalProducer<Menu, NSError> as wanted. Here's how what I then would do in my view model:
MenuService.fetchTodaysMenu()
|> observeOn(QueueScheduler.mainQueueScheduler)
|> start(next: { response in
self.mainCourse.put(response.mainCourse!)
}, error: {
println("Error \($0)")
})
It seems like there's no UIKit bindings yet as of RAC3 beta 4. Colin made some UIKit extensions himself to help him make these bindings I was looking for as well. These can be found here. Adding them to my project, made be able to do exactly what I wanted to:
self.mainCourse.rac_text <~ self.viewModel.mainCourse
Update May 25, 2015
After been working a lot more with ReactiveCocoa 3, I would like to answer 1) once again. By using catch, it's possible to do this in a more declarative manner. I ended up implementing a small helper function for this:
public func ignoreError<T: Any, E: ErrorType>(signalProducer: SignalProducer<T, E>) -> SignalProducer<T, NoError> {
return signalProducer
|> catch { _ in
SignalProducer<T, NoError>.empty
}
}
The function transforms any NSError to NoError making it possible to bind as I wanted to by doing MenuService.fetchTodaysMenu() |> ignoreError.
I open sourced my project as this might be a good starting point for others looking into ReactiveCocoa 3.0:
https://github.com/s0mmer/TodaysReactiveMenu
Update March 5, 2016
As highlighted in the comments, since Swift 2, the ignoreError function would now look like:
public func ignoreError() -> SignalProducer<Value, NoError> {
return flatMapError { _ in
SignalProducer<Value, NoError>.empty
}
}
Also, an extension library called Rex has also been made, where something similar has been added.
I would like to be able to annotate my types and methods with meta-data and read those at runtime.
The language reference explains how to declare attribute usages, but is it actually possible to declare your own attributes?
Reading would require some kind of reflection mechanism, which I was not able to find in the reference at all, so the second part of the question probably is - is there reflection possible. If these features are not available in Swift, can they be done with Objective-C code (but on Swift instances and types)?
A relatively unrelated note: The decision of what has been modelled as an attribute and what has been added to the core syntax strikes me as pretty arbitrary. It feels like two different teams worked on the syntax and on some attributes. E.g. they put weak and unowned into the language as modifiers, but made #final and #lazy attributes. I believe that once they actually add access modifiers, they will probably be attributes likes final. Is all of this somehow related to Objective-C interoperability?
If we take the iBook as definitive, there appears to be no developer-facing way of creating arbitrary new attributes in the way you can in Java and .NET. I hope this feature comes in later, but for now, it looks like we're out of luck. If you care about this feature, you should file an enhancement request with Apple (Component: Swift Version: X)
FWIW, there's really not a way to do this in Objective-C either.
You can now do something like this! Check out "Property Wrappers" - https://docs.swift.org/swift-book/LanguageGuide/Properties.html
Here's an example from that page:
#propertyWrapper
struct TwelveOrLess {
private var number = 0
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
}
struct SmallRectangle {
#TwelveOrLess var height: Int
#TwelveOrLess var width: Int
}
var rectangle = SmallRectangle()
print(rectangle.height)
// Prints "0"
rectangle.height = 10
print(rectangle.height)
// Prints "10"
rectangle.height = 24
print(rectangle.height)
// Prints "12"
I need a special keyword in my code to be replaced by a consequence of symbols before the build.
For example, I want hello to be replaced by Debug.Log("Hello");
According to this, MonoDevelop didn't have this feature in 2006. Has anything changed?
If no, are there any plugins/external tools implementing it?
I don't think that switching to another IDE will be helpful unless it can use code completion for unity3d.
Please, don't answer that macro definitions are evil.
Update:
I understood that my example was too abstract. In fact, I want to replace read("name"); with
var name;
name=gameObject.Find("name");
if(!name)
return;
name=name.param;
1)Every script should have all needed variables declared + a variable called "self".
2)They should be public.
3)
public static function set_var(target,name:String,value)
{
var fi=typeof(target).GetField(name);
fi.SetValue(target,value);
}
public static function read(name:String,target):String
{
set_var(target,"self",target);
return "var rtmp=self.gameObject.GetComponent(\""+name+"\");"+"if(!rtmp)return;"+name+"=rtmp.param;";
}
4)eval(read("name",this));
5)As far as I know, it wouldn't work in unity C#
6)Probably, set_var can be replaced by assignment
Far better solution:
var component_names = ["hello","thing","foo"];
var component;
for(var name:String in component_names)
{
component = gameObject.GetComponent(name);
if(!component)
return;
set_var(this,name,component.param);
}
(Requires set_var() from the first one)