How Can I Tap The Detail Button Of An UITableViewCell in Xcode UI Test? - xcode-ui-testing

I have an UITableViewCell configured with a detail button and an accessibility identifier:
private func configure(cell: UITableViewCell, at indexPath: IndexPath) {
let item = fetchedResultsController.object(at: indexPath)
// ...
cell.accessoryType = .detailButton
cell.accessoryView?.accessibilityLabel = "Item Details"
// ...
}
In the UI test method, I need to tap the detail button of the cell, which I attempt in the following method:
private func getScreenshotOfItemToEdit() {
app.tables.element(boundBy: 0).cells.element(boundBy: 0).buttons["Item Details"].tap()
itemQuantityTextField().tap()
itemQuantityTextField().typeText("2")
snapshot("04-EditItem")
saveItemBarButtonItem().tap()
}
The test fails at the first line, but I can't figure out why.
What do I need to change so that I can tap the detail button of the cell in my UI test?

To make sure that the item you're trying to interact with exists I would suggest you to print the application's debug description
print(XCUIApplication().debugDescription)
This will give you all the elements that are on the screen along with their accessibility identifier, label and value.
After using the code you provided, I wasn't actually able to set the accessibilityLabel of the accessoryView to "Item Details". Setting the accessibilityIdentifier did not work either.
The good new is that you can still access the detail button out of the box with the following code
// Accessing the detail button for the first cell
let cell = XCUIApplication().cells.element(boundBy: 0)
cell.buttons["More Info"]

Related

macOS NSTableView cell does not do anything

I have this line "func tableView(_ tableView: NSTableView, didClick tableColumn: NSTableColumn) {code here}"
This function does not do anything. I want to click a row in a table view and do some action when clicked it. But it does not do anything. The row is showed correctly, but action is missing. I added also "print("Clicked") in that function, but even that does not show on log information"
How else could I make this working?
From the documentation of tableView(_:didClick:): "Tells the delegate that the mouse button was clicked in the specified table column, but the column was not dragged.". This method isn't called when you click in a row. If you want to catch clicks in a tableview, subclass the table view, row view or cell view and override mouseDown(with:).
Another solution: let the table view handle the click and use the selected row. The delegate has several methods to detect changes in the selection.
Use NSTableView.selectionDidChangeNotification to detect selection
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.didSelectRow(_:)), name: NSTableView.selectionDidChangeNotification, object: tableView)
}
#objc
func didSelectRow(_ noti: Notification){
guard let table = noti.object as? NSTableView else {
return
}
let row = table.selectedRow
print(row)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
After test, i found it was triggered by click at column area. As its parameter says, "Did click table column", not table row.

Swift: How to keep ViewControllers in exact same condition?

I have two view controllers and in ViewController 1 I have a date picker and a text field. I have another ViewController that displays what you have entered in that date picker and text field. I have a ¨change¨ button that returns you to that first view controller and a ¨doen¨button that show view controller 2. As of now the text in the textfield and the date that the user has selected, is gone every time you close the app or click the ¨change button(Go back to View controller 1).
How can i keep the text in the text field, and the selected date in the date picker.
I want the user to be able to change the information that has already been added.
Please add code.
http://imgur.com/PDzJrNJ (Picture of the main storyboard)
The way you are showing the ViewControllers is not optimal. In the best case, when you show something new (ViewController2), then dismiss it, it should lead you back to the previous screen (ViewController1). It should not instantiate a new instance of ViewController1, as the segues in you case are doing.
Please note that depending on how you present the second view the solution would be different.
In case your segue from the first controller to the second is a "Show" segue, you can just add the following to your "Change" button:
#IBAction func changeButtonPressed(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
In case you have a navigation controller (I do not see such on the screenshot), then you can use
#IBAction func changeButtonPressed(sender: AnyObject) {
self.navigationController.popViewControllerAnimated(true)
}
What you could try doing is saving the data before exiting the view controller.
In the viewWillDisappear method, you could add
NSUserDefaults.standardUserDefaults().setObject(textField.text, forKey: "userText")
NSUserDefaults.standardUserDefaults().setObject(datePicker.date, forKey: "userDate")
Later, when you reopen the same view controller, in the viewDidLoad method, you could add
if NSUserDefaults.standardUserDefaults().objectForKey("userText") != nil {
textField.text = NSUserDefaults.standardUserDefaults().objectForKey("userText") as! String
}
if NSUserDefaults.standardUserDefaults().objectForKey("userDate") != nil {
datePicker.setDate(NSUserDefaults.standardUserDefaults().objectForKey("userDate") as! NSDate, animated: true)
}
I do not use date pickers very frequently, but I believe this is the correct code. Otherwise, it would be very similar. Hope this helps.

Using Swift, I want to add information into a screen but after the first use I do not want to see it again

Ok so here is my question.
I want to have a screen pop up right after my LaunchScreen exits and i want to be able to add information into it, however once I add that information into it, I do not want to see that screen again.
I will be using storyboard, swift and CoreData and Xcode 6.3 if that helps.
Thanks in advanece
NSUserDefaults is a really quick way of storing (small amounts of) data.
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setBool(true, forKey: "hasSeenStartup")
if(defaults.boolForKey("hasSeenStartup")){
println("Don't show")
}
First you will need to define a set of userDefaults, easiest is standardUserDefaults()
We can set a boolean value to a key (after we showed the popup screen) using setBool() this takes 2 parameters, the first is the boolean value, the second is a key for the value.
When the users launches the app, you will need to get the boolean value for the key. If the user already has seen the popup (it’s boolean value for hasSeenStartup will be set to true) you can skip the popup and show them the other viewController
EDIT:
Since your question seems to focus on showing the new view controller rather than saving the data. Here is some code on how to show a new view controller.
let storyboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: NewViewControllerClass = storyboard.instantiateViewControllerWithIdentifier(“newViewController") as! NewViewControllerClass
self.presentViewController(vc, animated: true, completion: nil)
To use this code you will need to change the:
Storyboard name to the name of your storyboard (defaults to “Main”)
Set the class of the viewController by replacing NewViewControllerClass with the class of (obviously) your new viewController.
Change the newViewController with the Identifier
You can than use this code to present the new ViewController. Present this viewController if your Core Data has info saved about the user and thus if the user has seen the initial screen.
I would advice to retrieve the Core Data inside the ViewDidAppear method inside your FirstViewController.
override func viewDidAppear(animated: Bool) {
if (check to see if core data is not empty){
let storyboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: NewViewControllerClass = storyboard.instantiateViewControllerWithIdentifier(“newViewController") as! NewViewControllerClass
self.presentViewController(vc, animated: true, completion: nil)
}
}

Custom cell in Xcode 6 + Swift not displaying

I've searched a lot on the internet for a solution to this problem but I can't figure it out. I'm trying to create a custom cell in a table view.
I made a CustomCell.swift class to configure the labels I want in my custom cell, created it via storyboard (the first prototype cell in the tableview) and linked it with a identifier to the cellForRowAtIndexPath method
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let cellIdentifier = "huisCell"
var cell: CustomCell? = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? CustomCell
if cell == nil {
cell = CustomCell(style: UITableViewCellStyle.Value1, reuseIdentifier: cellIdentifier)
}
cell!.huisAdresLabel.text = "123"
cell!.huisDetailLabel.text = "456"
return cell
}
My CustomCell.swift code is like this:
class CustomCell: UITableViewCell {
#IBOutlet var huisAdresLabel: UILabel
#IBOutlet var huisDetailLabel: UILabel
}
It's very basic now, but I just want it to work because than I can expand the cell with more attributes and style it better.
Pictures via DropBox because I need 10 reputation to properly document my problem :)
https://www.dropbox.com/sh/5v9jb6cqp80knze/AAD5-yPR8-KoStQddkqKIbcUa
I hope someone can explain what I'm doing wrong.
Edit:
To clear up some things, before my try to make a custom cell, I got it working with the basic cells, with the one label on the left hand side. But when I tried to style the tableview and created a custom cell it won't work.
Also, when testing different solutions I came across the problem that de two labels in CustomCell.swift are nil. Even when I made a custom init and did like a
self.huisAdresLabel = UILabel()
it was still nil. in the code that I showed you it prints the following:
<UILabel: 0xb2aadc0; frame = (0 -21; 42 21); text = '123'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0xb2aa3a0>>
I resolved this issue by overriding the following function, setting the height of the cells manually:
override func tableView(tableView:UITableView!, heightForRowAtIndexPath indexPath:NSIndexPath)->CGFloat
{
return 44
}
Try using a xib file and adding your custom cell class to the
"Table View Cell" that you create in your xib file.
(Make sure you reconnect it to the outlets in your custom cell class ;)
This link may help.
http://www.weheartswift.com/swifting-around/
I had the same Problem, but after disabling the "Use Auto Layout" under the "File Inspector", it did work!! and the Custom Cells are displayed
Note: I made the Custom Cells in the Builder, not in Code. Using Xcode beta 3
Working w/ Custom table cells in Xcode 6 Beta-4's IB, I found they all rendered on top of each other and my non-Custom cell.
I fixed my problem by...
selecting the Custom cell in IB
selecting the Size inspector (Option-Command-5)
in the Table View Cell section
checking the Custom box
keeping the default-provided 44 Row Height
Quick workaround: disable Use Size Classes, but still don't know is it bug or feature :-) needs more investigation or man reading.

Navgation Controller and UIImageView in a custom cell in UITableView

In my app's navigation controller is an UITableViewContoller then a ViewController. The user selects an item in the UITableViewContollrer, this calls the ViewController. If the user hits the back button I need to visually show which item was selected before. Doing this with a UIImage, basically want to hide or show it. Problem is I cannot find a method that will parse each cell in the UITableView and determine if the the cell was selected before when the UITable is called again.
Some background on the UITableView, it is based on an entity in core data. The selected item is stored in a different entity in core data.
Firstly declare NSIndexPath *selectedIndexPath and creates its property. Now in tableView Delegate:
- (void)selectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition
{
selectedIndexPath = indexPath;
}
You have selected IndexPath of cell in tableView. When hits back button of navigator bar, ViewControllers viewWillApper will be called
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(selectedIndexPath)
{
//if you have custom cell then you will get custom cell which was selected just use custom cell object in place of UITableViewCell
UITableViewCell *cell = (UITableViewCell*)[YourtableView cellForRowAtIndexPath:selectedIndexPath];
//You have cell reference which was selected when one view controller was pushed in navigation controller.
// you can change image or label text which are present in your cell
// cell.ImageView or cell.labelText anything
}
}
Hope it is useful.

Resources