how to get value from source code using calabash iOS - ios

I am using calabash cucumber to test my IOS application. The issue is for doing validations and some other operations. I need to get value from the source code. Is it possible? If so, how? Please help me. I have gone through different documentations, but I did not get a proper answer. Thanks in advance.

You can using the calabash-ios query language to call selectors on UIView and its subclasses.
If you have any experience with calabash-ios you probably have been using this feature without realizing it.
# calls the 'text' selector on the labels that match the query
query("label marked:'product description'", :text)
To see if a button is enabled, you could do the following:
# NB the property is 'enabled', but the selector is 'isEnabled
query("button marked:'ask for help'", :isEnabled")
This is described on the calabash-ios wiki:
https://github.com/calabash/calabash-ios/wiki/03.5-Calabash-iOS-Ruby-API
https://github.com/calabash/calabash-ios/wiki/05-Query-syntax

If you want to set custom attributes then one way to do it is to subclass a UI element (such as UIButton and then you can create a property which you can then access like so:
ExampleButton.h:
#interface ExampleButton : UIButton
{
BOOL doingSomething;
}
#property (nonatomic) BOOL isDoingSomething;
ExampleButton.m
#import "ExampleButton.h"
#implementation ExampleButton
... //code possibly here
- (BOOL)isDoingSomething
{
return doingSomething;
}
... //more code possibley here
and then you would have other code that sets doingSomething.
By the way I've only just started out in iOS and Calabash testing so I my objective C is rusty, but I think you can also not have the doingSomething Bool and just have #synthesize isDoingSomething which you can then get and set on the property directly (self.isDoingSomething = true; etc).
In calabash your query would look like this then:
query("view:'ExampleButton' isDoingSomething:1")
or
query("view:'ExampleButton' isDoingSomething:0")
to see if the property is true or false respectively.
This is probably not the only way to do it (it probably isn't even the easiest way to do it but it works).

Related

No known class method for selector 'simplePingWithHostName: SimplePing iOS Objective C

Hello I am having trouble using SimplePing I receive the following error when copying over the SimplePing.h and SimplePing.m files I downloaded from Apple SimplePing
No known class method for selector 'simplePingWithHostName:'
From this method in my SimplePingClient.m class:
-(void)pingHostname:(NSString*)hostName andResultCallBlock:(void(^)(NSString* latency))result
{
_resultCallback = result;
_pingClient = [SimplePing simplePingWithHostName:hostName]; // No known class method for selector 'simplePingWithHostName:'
_pingClient.delegate = self;
[_pingClient start];
}
I'm calling this method from another file like this, where there are no errors:
-(void)testNetworkLatency {
[SimplePingClient pingHostname:#"www.apple.com"
andResultCallback:^(NSString *latency) {
NSLog(#"your latency is: %#", latency ? latency : #"unknown");
}];
}
I tried changing [SimplePing simplePingWithHostName... in SimplePingClient.m to variations of pingHostname, initWithHostName, sendPingWithData but nothing has worked so far. Did something change with SimplePing or am I going wrong somewhere?
Link to a screenshot of all the methods available in SimplePing.h as you can see, there is no simplePingWithHostName
it is wise to read the class definitions before coping and pasting but once done you can take them for granted because thats what they are for. You will have much more fun when following them. But keep on trying as this is a classic beginner mistake in objC when taking over language concepts from elsewhere but not objC.
You will want to set a global variable to keep your simple ping object around.
#implementation YourClass {
SimplePing *_pingClient;
}
alternative in
#interface YourClass : YourInheritingClass <NeverGiveUpProtocol>
#property (nonatomic) SimplePing *pingClient;
#end
and in your implementation method allocation and initiation of your ping object is done like
_pingClient = [[SimplePing alloc] initWithHostName:hostName];
Also you will have to be careful with the definition of block parameters that are doing nothing and are set up to accept NSStrings. You can read about block definitions in methods here
https://riptutorial.com/objective-c/example/1761/blocks-as-method-parameters
You can tell the compiler that you don't need a specific parameter like so ..
if you cant avoid to define it.
-(void)yourmethod:(NSString*)hostname resultBlock:(void(^)())result {
#pragma unused(result)
// your stuff
}
Hint: SimplePing and SimplePingClient seem to be total different classes where the last one contains pingHostname: as external method. (Means you can call it without explicit initiation.) Ending up in a method definition like..
+(void)pingHostname:(NSString *)hostname; which is why you would need to call it directly on the ClassName.
The Apple example does not contain a class named SimplePingClient.
Thats probably result of your creative process. Yeah maybe you want to ping from the app you create to the same app on a different device - well, why not. Cheers

How to create a new object and assign properties in Objective-C?

I'm trying to bridge an Objective C SDK with React Native and I'm having some trouble. I have a Subclass of NSObject and I'm trying to set some property values but I can't get it to work.
I have tried to change the property in the header, and in the imp file with out any difference.
PrinterSDK.h (which has libPrinterSDK.a)
#interface Printer : NSObject
#property (nonatomic, readonly) NSString* name;
#property (nonatomic, readonly) NSString* UUIDString;
#end
RNPosPrint.m
#interface Printer ()
#property (readwrite) NSString* name;
#property (readwrite) NSString* UUIDString;
#end
RCT_EXPORT_METHOD(printTestPaper:(NSString*)name:(NSString*)uuid)
{
Printer* printer = [[Printer alloc] init];
printer.name = name;
}
But I keep facing issue with the setter for some reason I can't figure out.
ExceptionsManager.js:94 Exception '-[Printer setPrinterName:]: unrecognized selector sent to instance 0x13fd25b90' was thrown while invoking printTestPaper on target RNPosPrint with params (
"Test Printer",
"XXX-XXX-XXX"
)
You do not report the names of your .h and .m files or what else is in the .m – e.g. #implementation of Printer? The class printTestPaper belongs to? Without details like this it is difficult for anyone to help you, you need to help people help you.
That said some points that may help you:
The #interface Printer () where you open up the properties to be writeable should be in the your Printer.m file – in general do not try to open up access to a type's properties from outside the type's implementation, it is both bad design and may not work as you hope (as you just found out).
The code to support a #property is generated by the compiler when it compiles the #implementation, #interface's themselves produce no executable code – they describe the accessible parts of the #implementation.
setter=<name> provides a different name for the auto-created property setter function. While a method <name> will be created to set the property using dot syntax the properties name is still used, e.g. in your case printer.name = ... is still used even with the setter=setPrinterName:. You can call the auto-created method using standard method syntax, that failed in your case for the reasons above.
Using setter=<name> or getter=<name> are really advanced features and you probably will never need to use them – when you do need to use them you will know! Just avoid them till then.
If you wish to provide a method which creates the object and sets properties then do this in the type's implementation. The usual way of doing this is to provide an init method that does this, e.g. in this case it might be - initWithName:(NSString *)printerName { ... }, or an equivalent class method which does the allocation and sets the parameters, e.g. in this case it might be + newWithName:(NSString *)printerName { ... }.
HTH
Since it's an interface from statically linked library it is simply not possible to extend or manipulate. Not without tempering with the compiler.

How to Implement native module in react-native?

I am following this guide
http://facebook.github.io/react-native/docs/nativemodulesios.html#content
And also this website:
http://colinramsay.co.uk/2015/03/27/react-native-simple-native-module.html
But does not matter where i add the .h and .m files i always get the error:
Class ClassName was not exported Did you forget to use RTC_EXPORT_MODULE()?
Even if it the same code from the examples from react-native documentation, can anyone guide me where to add the .h and .m files and properly link them to the project?
Thanks.
There has been a change in the native module API and it seems the docs haven't been updated accordingly. From the example in my article, SomeString.m should look like this:
// SomeString.m
#import "SomeString.h"
#implementation SomeString
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(get:(RCTResponseSenderBlock)callback)
{
// Change this depending on what you want to retrieve:
NSString* someString = #"something";
callback(#[someString]);
}
#end
This ends up with the desired result and you can call it from JS in the same way as before. It looks like this only just happened:
https://github.com/facebook/react-native/commit/0686b0147c8c8084e4a226b7ea04585362eccea8
You can also just add a plain RCT_EXPORT(); to any method you want to export. Works like a charm.

Generate custom init method automatically

Is it possible to generate custom init method automatically from Xcode, as Android Studio does for android?
I mean, if I declare some properties in .h, for example:
int a;
int b;
So, I would like to create automatically a init method as:
- (id)initWithA:(int) aInner andB:(int) bInner
{
a = aInner;
b = bInner;
}
New Xcode (after Xcode 10) support this issue for class (not for struct).
Steps:
right click on class name
click "refactor"
click "Generate Memberwise Initializer"
As for struct. You can make it class first, and change it back to struct after you get auto-gen init.
While there's still no way to do this automatically (without installing a plugin), there's a neat trick to convert a list of property declarations to assignments using multiple cursors:
Copy the list of properties and paste it into your constructor
Use Shift+Ctrl + click to insert multiple cursors (Shift+Ctrl+↑/↓ work as well)
Edit with multiple cursors to assign values
Credits go to Paul Hudson: Xcode in 20 Seconds: Multiple cursors
There is no native way of doing this, however you can install XCode extensions that will add support for this.
See this following extension as this will provide the feature you are after (Swift version).
https://github.com/Bouke/SwiftInitializerGenerator
Yo can create a snippet. You need to play with it a bit, create nice blue placeholders where relevant but most importantly, attach a keyboard shortcut to it. For example "initx"
Then you just start to type the shortcut in line where you want the initialiser to be and voila, you have your custom init.
Yes you can initialise an class by custom init method or you can pass parameter when you want to initialise class with custom init method
look
Define in your class.h file
#interface CustomView : UIView
- (id)initWithA:(int) aInner andB:(int) bInner
In .m file implement initWithStringMethod.
- (id)initWithA:(int) aInner andB:(int) bInner
{
if((self = [super init]))
return self;
}
initialised class from other class or viewController
CustomView *cv = [[CustomView alloc] initWithA:5 andB:10 ];

Run unittests with a specific locale (en_US or none)

Is there a way to force a specific locale when running unittests?
Eg. always use en_US or force no locale, so that none of the .lproj files are loaded.
My unittest is sensitive to the currently selected language in the Settings app (in the iOS Simulator). Preferably I would like my unittests not to be language sensitive.
Below is my unittest code that shows the problem
#interface MYGalleryTests : SenTestCase
#end
#implementation MYGalleryTests
-(void)test0 {
// This test doesn't work.
// I get 'No pictures' when locale is en_US
// I get 'Ingen billeder' when locale is da_DK
NSString* actual = [MYGallery emptyMessage];
NSString* expected = #"EMPTY_MESSAGE";
STAssertEqualObjects(actual, expected, nil);
}
#end
#interface MYGallery : NSObject
+(NSString*)emptyMessage;
#end
#implementation MYGallery
+(NSString*)emptyMessage {
return NSLocalizedStringFromTable(#"EMPTY_MESSAGE", #"Gallery", #"Message shown when gallery is empty");
}
#end
en.lproj/Gallery.strings
/* Message shown when gallery is empty */
"EMPTY_MESSAGE" = "No pictures";
da.lproj/Gallery.strings
/* Message shown when gallery is empty */
"EMPTY_MESSAGE" = "Ingen billeder";
There is a way to run the unit tests in a specific locale, but it isn't good for unit testing, but it can be useful for testing.
In Xcode, go to Product -> Scheme -> Edit Scheme… -> select Test -> Options and then set the 'Application Language' popup to the desired language. Then your unit tests will run in the specified language. You can use this to test code for a specific locale. You can use this to get faster test turnaround than actually running your app, especially if you only run a specific subset of unit tests. However, it is not useful for unit testing in general because you're limited to the specified language.
Also, doing this will modify your .xcscheme, so you'll need to change that back when you're done.
One way to change the locale for unit testing is to use the technique specified here. However, that technique uses method swizzling, which doesn't work with Swift.
Just specify the lang in run options.
Posting a proper answer so you can mark this as answered.
How to force NSLocalizedString to use a specific language has a solution for this problem.

Resources