Over a million developers have joined DZone.

JavaScript for OS X Automation by Example

DZone's Guide to

JavaScript for OS X Automation by Example

· DevOps Zone
Free Resource

“Automated Testing: The Glue That Holds DevOps Together” to learn about the key role automated testing plays in a DevOps workflow, brought to you in partnership with Sauce Labs.

Written by Michael Crump 

Apple is very close to releasing a new operating system called Yosemite. Everyone has been talking about iOS 8, iPhone 6, iPhone 6 Plus and watches, but one important feature was JavaScript for OS X Automation. While it may have been overlooked by journalists, it was not overlooked by Telerik. Burke Holland created an excellent post that described how JavaScript is now a first-class citizen. In this post, I am going to show you how you can use JavaScript for OS X Automation, since there is hardly any information on it besides the preliminary documentationon Apple’s site.

Note: I am using APIs still in development. Anything shown below is subject to change.

Getting Started

After you have installed Yosemite, then go to “Applications” -> “Utilities” and drill down until you see the Script Editor as shown in Figure 1

Figure 1 : Script Editor.

Figure 1 : Script Editor.

Previously, your only option for creating automated tasks was AppleScript, now you will see JavaScript has been added.


Select JavaScript and let’s build something.

Example: Automating an Email Message

If you have automated tasks in the past, then surely you have interacted with the Mail app. Below is a snippet written in AppleScript.

tell application "Mail"
    set theMessage to make new outgoing message with properties 
     {visible:true, subject:"Thanks for buying from us!", content:"My Body"}   
end tell

I’ve taken the same snippet and appended slightly more complex content, but wrote it entire using JavaScript.

Mail = Application('Mail');

content = "Hi Michael,\n\n"
      + "Hello, How are you! \n\nThanks for stopping by today!"
      + " We really appreciate your business \n\n"
      + "Sincerely,\n\n"
      + "Company Name";

msg = Mail.OutgoingMessage({
    subject: "Thanks for buying from us!",
    content: content,
    visible: true



A couple of things to note here:

  • Semicolons are optional because of Automatic Semicolon Insertion (ASI).
  • I instantiated a variable in the global scope; instead of using for example :
    var Mail = Application(‘Mail);
  • I can use either single or double quotes for hard coded values.

If this script is run, then the following email dialog will appear as shown in Figure 2

Figure 2 : Email Message with Fields populated.

Figure 2 : Email Message with Fields populated.

But How Do you Know What Properties are avaiable?

Good question, if you are inside of Script Editor then you can click on “Window” -> “Library” to see a list of available apps that you can interact with. If we pick the Mail app then it will default to AppleScript, simply change that to JavaScript and you can see the properties that are available on the OutgoingMessage class that we just used inFigure 3.

Figure 3 : Examining the OutgoingMessage class from the Documentation.

Figure 3 : Examining the OutgoingMessage class from the Documentation.

That’s Cool, but What About Other Applications?

The Notes app is another application that we can interact with, but Apple has put in security precautions to prevent malicious scripts. We can interact with the Notes app with just a few lines of JavaScript.

Notes = Application('Notes');

SystemEvents = Application('System Events');
Notes = SystemEvents.processes['Notes'];


If you run this application, then you will be greeted with the following dialog shown in Figure 5.

Figure 5 : Security & Privacy Dialog.

Figure 5 : Security & Privacy Dialog.

If you click on “Open System Preferences”, then you can grant this script access and the Notes app will open automatically.

I’m sure by now you are wondering how to run these scripts without being inside the Script Editor application. You can do so by clicking on “File” -> “Export” then change the format to “Application” as shown in Figure 6.

Figure 6 : From a script to an app!

Figure 6 : From a script to an app!

Other Automation Tasks

You may not want to interact with an application, maybe you wish for your app to speak to the user. You can accomplish this with just a few lines of JavaScript

App = Application.currentApplication();
App.includeStandardAdditions = true;
App.say("Hello from Telerik Headquarters");

This will use the default voice and language installed on your system to speak the words, “Hello from Telerik Headquarters”.

You can also use it to capture input such as a Name for example:

App = Application.currentApplication();

App.includeStandardAdditions = true;

answer = App.displayDialog('Please enter your Name', {
  withTitle: 'Name',
  defaultAnswer: 'Telerik'

This will display a prompt (Figure 7) and you can see in the Results window what they actually typed (Figure 8). In this case, I typed my name, “Michael”.

Figure 7 : Dialog Message from JavaScript Automation

Figure 7 : Dialog Message from JavaScript Automation

Figure 8 : Results Window

Figure 8 : Results Window

JavaScript Automation can also be Accessed through the Terminal

Surprisingly enough, JavaScript Automation can also be helpful for those that use bash to automate tasks. Here is an example command line that opens Safari and a new tab and navigates to http://www.telerik.com by usingosascript interactive mode. The rest is plain JavaScript that we talked about before.

osascript -l JavaScript -i
Safari = Application("Safari");
window = Safari.windows[0];
tab = Safari.Tab({url:"http://www.telerik.com"});
window.currentTab = tab;

The below screenshot shows what it looks like in the terminal window in Figure 9

Safari will open and generate a new tab as shown below:


Look back through the terminal window and notice that when I called window.name() it returned “Top Sites”. This could be useful for understanding what page a user is on.

There’s an Objective-C Bridge to Advantage Of

This is useful if you wish to use frameworks not present in the Foundation framework used by default. You can take advantage of frameworks like Cocoa by implementing the following code.

str = $.NSString.alloc.initWithUTF8String('Writing text to file through obj-c bridge.');
str.writeToFileAtomically('/Users/MichaelCrump/FromObjCBridge.txt', true);

This code imports the Cocoa Framework, initializes an NSString with text and calls thewriteToFileAtomically method passing in the file location and setting the second pararameter to true. This will ensure that the old file will not be changed or removed until the new version is completely on the disk.

We can navigate to our folder and open the text file and see the expected results in Figure 10

Figure 10 : Obj-C Bridge Writing a File to Disk

Figure 10 : Obj-C Bridge Writing a File to Disk

Even more Opportunities for JavaScript Developers

We are learning more and more about the implications of JavaScript becoming a first-class citizen in Yosemite. It is also front and center for NativeScript. NativeScript enables developers to use JavaScript to build native apps leveraging readily available or custom device APIs, such as those for camera, accelerometer, geolocation and more. There is a lot to talk about with NativeScript, but I’ll point you to the FAQ if you want to learn more.

NativeScript allows you to build native applications for iOS, Android and Windows Universal using JavaScript.

Bright Future Ahead

I’m very excited about what I’ve seen so far with JavaScript for OS X Automation. Prior to writing this article, I’d never used AppleScript before, but had written JavaScript. I was able to use the syntax familiar to me and successfully write automation tasks. JavaScript developers all over the world should rejoice even if they don’t plan on writing automation tasks because it shows that skillset is becoming more and more important.

Learn about the importance of automated testing as part of a healthy DevOps practice, brought to you in partnership with Sauce Labs.


Published at DZone with permission of Doug Winfield, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}