Using an URL scheme in XCTestCase - objective-c

I want to run a test which awaits the response of a browser.
A test target has an Info.plist where I can register custom URL schemes. But those are never called. I know that an test target is not a real application.
Is there a way?
EDIT (for bounty): I want to write an integration test for a class that calls openUrl("tel://" + some phone number). How do I subscribe to this URL scheme in an XCTestCase?

The question was retagged to OS X so my answer is no longer valid
Original answer
This is impossible. The basic reason is that the tests are connected to one running application instance, they have no control over the device, they are running as part of the application. You can probably open the URL but you won't be able to return to the application and do an assert.
Also note that XCUnit is a unit testing framework. You won't be able to write advanced integration test in it. You might be more successful with UI Automation but this specific test case will be very complicated even for it. For example, to open a link by your app in the simulator, you can create a HTML page that will redirect to the link and then use shell to exec open testLink.html -a "iOS Simulator". However, in my humble opinion this kind of tests is unreliable and realy hard to write and debug.
My advice would be to:
Write an unit test that mocks [UIApplication openURL:] and verify that you are passing a correct URL to it. Or if you want the other direction, write a unit test that will call UIApplicationDelegate methods in the called order, simulating opening a link by your app. This is as far you can go with XCUnit.
Test the rest manually.

I am uncertain what exactly that you are trying to test. I assume that it is something more than whether the URL can be opened or not. The test case below checks whether FaceTime will open and can open a URL. If the app you are testing registers a custom scheme, then simply changing pathToTestApplication should work.
class NSURL_SchemeTests: XCTestCase {
func testWhoHandlesSchemeTel() {
let testAppURL = NSURL(string: pathToTestApplication)
// create a NSURL for the test
let tel = "tel:5555555555"
let url = NSURL(string: tel)
XCTAssert(url != nil, "Could not create a URL from \(tel)")
// determine whether any application is registered to handle the URL
let workspace = NSWorkspace.sharedWorkspace()
let urlHandler = workspace.URLForApplicationToOpenURL(url!)
XCTAssert(urlHandler != nil, "No application found to open URL \(tel)")
// determine whether the expected test application is registered to handle the URL
XCTAssert(urlHandler! == testAppURL,
"Application \(pathToTestApplication) was not registered to handle URL \(tel)")
// attempt to open the URL
XCTAssert(workspace.openURL(url!), "Could not open URL \(tel)")
}
}

Related

How can I automatically run an AppleScript when Safari.app starts?

Basically I want make sure I execute a custom written .applescript every time Safari is opened.
I tried adding the script to the "~/Library/Scripts/Applications/Safari" folder but that doesn't seem to automatically do it.
As a workaround I can probably just write an AppleScript that both starts Safari and runs my custom stuff. I just wanted to check whether there's a cleaner way of doing this.
Putting stuff in the ~/LibraryScripts/Applications folder just makes them available when the particular application is active.
In addition to your alias that runs the script and Safari, you could use some AppleScriptObj-C in a background application (maybe run via login items) that registers for NSWorkspaceDidLaunchApplicationNotification notifications to get the names of applications as they are launched. This would also have the advantage of seeing when Safari gets launched other than from your alias, such as via various document links (Mail, PDFs, etc):
use framework "Foundation"
my addObserver:me selector:"appLaunchNotification:" |name|:(current application's NSWorkspaceDidLaunchApplicationNotification) object:(missing value)
on appLaunchNotification:notification -- an application was launched
# notification's userInfo contains the application that was launched
set applicationInfo to NSWorkspaceApplicationKey of notification's userInfo -- NSRunningApplication
set appName to (localizedName of applicationInfo) as text
-- do your thing depending on appName
end appLaunchNotification:

Firefox Web Extension API - Get Downloads Folder

Is it possible using the web extensions API to get the default download folder for the current profile? I need to send it via native messaging to an external app.
I feel like https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/downloads should have it but it does't seem to.
Your best bet is probably making a dummy download and sending the "filename" property that you get back as a variable to your external app.
You would use the browser.downloads.onChanged event to get a reference to the filename value:
browser.downloads.onChanged.addListener(listener);
function listener(changed){
if(changed.filename != null){
// Do something
// Remove downloads.onChanged listener
browser.downloads.onChanged.removeListener(listener);
}
}
browser.downloads.download({url: dummyUrl});
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/downloads/onChanged

Objective C - "Reset Content and Settings" programmatically in test files

I am playing around with the new UI testing introduced in Xcode 7 beta. In one of my UI testing scenarios, I need to add some code that does the same thing as clicking Simulator -> Reset Content and Settings in the setup() of my test file, which is a XCTestCase. Can the reset be done programmatically? Or, can we mimic the effect of a factory reset on an app in test code?
Not entirely programmatically, but you can always write a bash file to delete:
${user.home}/Library/Application Support/iPhone Simulator/${simulator.version}
That will clear the settings on the simulator.
My understanding is that you won't be able to that from within your app, as apps are sandboxed.
Usually people were using shell scripts or apple scripts. However, using hard reset is absolutely not necessary.
You shouldn't care about data in other apps, you should care only about the data in your app. You can always delete your app data (files, user defaults) in the beginning of your tests. So, why should you do a hard reset?
A better solution is mocking. If your test supposes that, for example, some variable in NSUserDefaults is not set, you don't have to care about the actual value stored there, just mock the method your implementation is using (e.g. objectForKey: and let it return nil.

testing existing pages with mocha-phantomjs

I'm not quite getting how to use PhantomJS and Mocha together, specifically through mocha-phantomjs.
I've read some tutorials (the one at tutsplus is quite helpful) and am not seeing how I can test external pages using Phantom and Mocha. I'm sure I just need a nudge.
In the tutorial the author creates a tests.js file with some DOM setup/manipulation, as well as some mocha assertions. Then, he creates a separate HTML file that loads the tests.js file and uses mocha-phantomjs to fire up phantom and run the tests.
That's where I'm a little confused, how the mochaPhantomJS.run() method actually does things behind the scenes, whether it knows to search the js file for a describe block and run all tests within, that sort of thing. I don't need chapter and verse, but a high-level summary would be ideal.
Also, if I want to test an outside page, how can I best do that? In the tutorial all the DOM investigation and testing is done on the test page. If I want to test a different page, do I change or setup my assertions differently? Should I call the PhantomJS API from those tests and point to an external site?
Mocha will run tests that have been specified in javascript that has been included in the html page that is launched. If you look at the example html page on mocha-phantomjs it expects the test definitions using describe/it calls to be in the test/mycode.js file. If you put something like
These tests are only testing what is in the main file and associated javascript, there isn't anything special that mocha-phantomjs provides to test external html files. If you want to test your own html files I think you can head in a couple of directions, I came up with these:
first option: Create a way to load the parts of you app that you want to test into the main testing html file. How to do this depends a lot on your application setup. It is probably well-suited for a modular system. Just include the javascript from your application and test it. Not so good for full-page-html tests.
second option: Open new windows with the pages to test from the main testing html file (from within phantom that is). You can open a page using window.open() just like a normal browser. I created a proof of concept like this:
describe('hello web', function () {
it('world', function (done) {
var windowReference = window.open("fileundertest.html");
// windowReference.onload didn't work for me, so I resorted to this solution
var intervalId = window.setInterval(function () {
if (windowReference.document && windowReference.document.readyState === 'complete') {
window.clearInterval(intervalId);
expect(windowReference.document.title).to.equal("File Under Test");
done();
} else {
console.log('not ready yet');
}
}, 10);
});
}
)
This solution is relatively simple, but has the same drawbacks as any page-loading solution: you never know when the page is fully initialized and have to resort to some sort of timeout/wait system to wait for the page to get into the correct state. If you want to test a lot of separate html files these delays start to add up. Additionally waiting for 'onload' on the page that I opened wouldn't work so I created my own function based on setInterval and a (non-perfect) test on the document that was being loaded. I found out there are differences in behavior between loading an html page from the filesystem and loading the same page via a web-server.
third option: Create a mocha test that you run nodejs-style from the command line, and launch phantomjs with a specific page as part of your mocha tests. This is what I'd say you need if your system really depends on html pages that are quite different from each other.
I quickly tested the third option, here is my test based on the example I found on the phantom page (which is an alternative solution to phantomjs that is used by mocha-phantomjs -- I've used neither for more than brief experiments so I cannot recommend which one to use)
'use strict';
var chai = require('chai'),
phantom = require('phantom');
var expect = chai.expect;
describe('hello node', function () {
it('world', function (done) {
phantom.create(function (ph) {
ph.createPage(function (page) {
page.open("http://www.google.com", function (status) {
console.log("opened google? ", status);
page.evaluate(function () { return document.title; }, function (result) {
console.log('Page title is ' + result);
ph.exit();
expect(result).to.equal("Google");
done();
});
});
});
});
});
}
)
While it is possible to test this way I'd say that maybe the overhead of the communication between the code in the phantom-world and the testing code in the nodejs world isn't worth it. You can of course move a lot of general functionality to a couple of helper functions, but you are still stuck with having to call page.evaluate() to perform specific tests on the page. The same issues with timeouts/waits as above apply.
As an aside: do already know CasperJS? Maybe it can be helpful for your setup should you choose to build something on 'plain' phantomjs.

If-else in testcomplete

I have application "Application" , which have same autorization service as skype, QQ etc (You must log using yours login/password)
I need to test some functionality in settings of this application, so I`m using testcomplete :
I need tu run application
Go to settings
Change something
Save
And its quite simple. But if you are logged of, I need to reproduce such scenario:
run application
1.1. if logged of - log using (testlogin/testpassword)
Go to settings
Change something
Save
How I can reproduce such functionality in TestComplete?
I`m newbie with it so I need help :)
Thanks
Make your test check whether the login window is displayed. You can do this using one of the Wait* methods. If the login window is displayed then call a test routine/keyword test that will perform a login and then continue the general test flow.
...
var loginWindow = Sys.Process("Application").WaitWinFormsObject("loginDialog", 3000);
if (loginWindow.Exists) {
doLogin();
}
...
function doLogin()
{
// perform login
}
While your answer is totally right, I'd like to know if this is possible:
If the loginWindow does not exist, TC gives an error, is it possible to ignore this error and keep it out of the log besides locking the log or disabling it?
Like in Java or C#:
if(object.Exists)
do something;
else
do other thing;
this throws an error in TC and I don't want it to because I'm already checking for the existence of the object...
You cannot use a method on a object that is not there.
Workaround would be to first check for an object and then to use the Exists method like so..
if (object && object.Exists) {
// doSomething
} else {
// doSomethingElse
}