mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-12-26 01:53:13 +08:00
fix(launch-services): Use the same approach on all Mac OS X versions
This commit is contained in:
parent
70b260b285
commit
2fc89f7d6f
2 changed files with 127 additions and 284 deletions
|
@ -2,7 +2,6 @@ exec = require('child_process').exec
|
|||
fs = require('fs')
|
||||
|
||||
bundleIdentifier = 'com.inbox.edgehill'
|
||||
launchServicesPlistPath = "#{process.env.HOME}/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist"
|
||||
|
||||
module.exports =
|
||||
class LaunchServices
|
||||
|
@ -16,92 +15,48 @@ class LaunchServices
|
|||
available: ->
|
||||
@getPlatform() is 'darwin'
|
||||
|
||||
isYosemiteOrGreater: (callback) ->
|
||||
fs.exists launchServicesPlistPath, (exists) =>
|
||||
callback(exists)
|
||||
getLaunchServicesPlistPath: (callback) ->
|
||||
secure = "#{process.env.HOME}/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist"
|
||||
insecure = "#{process.env.HOME}/Library/Preferences/com.apple.LaunchServices.plist"
|
||||
|
||||
fs.exists secure, (exists) =>
|
||||
if exists
|
||||
callback(secure)
|
||||
else
|
||||
callback(insecure)
|
||||
|
||||
readDefaults: (callback) ->
|
||||
return callback(@_defaults) if @_defaults
|
||||
@isYosemiteOrGreater (result) =>
|
||||
if result
|
||||
@_readDefaultsSecure(callback)
|
||||
else
|
||||
@_readDefaultsPreYosemite(callback)
|
||||
|
||||
_readDefaultsSecure: (callback) ->
|
||||
@secure = true
|
||||
tmpPath = "#{launchServicesPlistPath}.#{Math.random()}"
|
||||
exec "plutil -convert json \"#{launchServicesPlistPath}\" -o \"#{tmpPath}\"", (err, stdout, stderr) =>
|
||||
return callback(err) if callback and err
|
||||
fs.readFile tmpPath, (err, data) =>
|
||||
@getLaunchServicesPlistPath (plistPath) =>
|
||||
tmpPath = "#{plistPath}.#{Math.random()}"
|
||||
exec "plutil -convert json \"#{plistPath}\" -o \"#{tmpPath}\"", (err, stdout, stderr) ->
|
||||
return callback(err) if callback and err
|
||||
try
|
||||
data = JSON.parse(data)
|
||||
callback(data['LSHandlers'], data)
|
||||
fs.unlink(tmpPath)
|
||||
catch e
|
||||
callback(e) if callback and err
|
||||
|
||||
_readDefaultsPreYosemite: (callback) ->
|
||||
@secure = false
|
||||
exec "defaults read com.apple.launchservices LSHandlers", (err, stdout, stderr) =>
|
||||
return callback(err) if callback and err
|
||||
|
||||
# Convert the defaults from Apple's plist format into
|
||||
# JSON. It's nearly the same, just has different delimiters
|
||||
plist = stdout.toString()
|
||||
regex = /([a-zA-Z]*) = (.*);/
|
||||
while (match = regex.exec(plist)) != null
|
||||
[text, key, val] = match
|
||||
val = "\"#{val}\"" unless val[0] is '"'
|
||||
plist = plist.replace(text, "\"#{key}\":#{val},")
|
||||
plist = plist.replace(/\(/g, '[')
|
||||
plist = plist.replace(/\)/g, ']')
|
||||
plist = plist.replace(/[\s]*,[\s]*\n[\s]*}/g, '\n}')
|
||||
|
||||
json = []
|
||||
if plist.length > 0
|
||||
json = JSON.parse(plist)
|
||||
|
||||
callback(json)
|
||||
fs.readFile tmpPath, (err, data) ->
|
||||
return callback(err) if callback and err
|
||||
try
|
||||
data = JSON.parse(data)
|
||||
callback(data['LSHandlers'], data)
|
||||
fs.unlink(tmpPath)
|
||||
catch e
|
||||
callback(e) if callback and err
|
||||
|
||||
writeDefaults: (defaults, callback) ->
|
||||
@_defaults = defaults
|
||||
if @secure
|
||||
@_writeDefaultsSecure(defaults, callback)
|
||||
else
|
||||
@_writeDefaultsPreYosemite(defaults, callback)
|
||||
@getLaunchServicesPlistPath (plistPath) ->
|
||||
tmpPath = "#{plistPath}.#{Math.random()}"
|
||||
exec "plutil -convert json \"#{plistPath}\" -o \"#{tmpPath}\"", (err, stdout, stderr) ->
|
||||
return callback(err) if callback and err
|
||||
try
|
||||
data = fs.readFileSync(tmpPath)
|
||||
data = JSON.parse(data)
|
||||
data['LSHandlers'] = defaults
|
||||
data = JSON.stringify(data)
|
||||
fs.writeFileSync(tmpPath, data)
|
||||
catch error
|
||||
return callback(error) if callback and error
|
||||
|
||||
_writeDefaultsSecure: (newDefaults, callback) ->
|
||||
@_readDefaultsSecure (currentDefaults, entireFileJSON) =>
|
||||
entireFileJSON['LSHandlers'] = newDefaults
|
||||
data = JSON.stringify(entireFileJSON)
|
||||
tmpPath = "#{launchServicesPlistPath}.json"
|
||||
fs.writeFile tmpPath, data, (err) =>
|
||||
return callback(err) if callback and err
|
||||
exec "plutil -convert binary1 \"#{tmpPath}\" -o \"#{launchServicesPlistPath}\"", =>
|
||||
fs.unlink(tmpPath)
|
||||
@triggerSystemReload(callback)
|
||||
|
||||
_writeDefaultsPreYosemite: (defaults, callback) ->
|
||||
# Convert the defaults JSON back into Apple's json-like
|
||||
# format. (I think it predates JSON?)
|
||||
json = JSON.stringify(defaults)
|
||||
plist = json.replace(/\[/g, '(')
|
||||
plist = plist.replace(/\]/g, ')')
|
||||
regex = /\"([a-zA-Z^"]*)\":\"([^"]*)\",?/
|
||||
while (match = regex.exec(plist)) != null
|
||||
[text, key, val] = match
|
||||
plist = plist.replace(text, "#{key} = \"#{val}\";")
|
||||
|
||||
# Write the new defaults back to the system
|
||||
exec "defaults write ~/Library/Preferences/com.apple.LaunchServices.plist LSHandlers '#{plist}'", (err, stdout, stderr) =>
|
||||
return callback(err) if callback and err
|
||||
@triggerSystemReload(callback)
|
||||
|
||||
triggerSystemReload: (callback) ->
|
||||
exec "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user", (err, stdout, stderr) ->
|
||||
callback(err) if callback
|
||||
exec "plutil -convert binary1 \"#{tmpPath}\" -o \"#{plistPath}\"", ->
|
||||
fs.unlink(tmpPath)
|
||||
exec "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user", (err, stdout, stderr) ->
|
||||
callback(err) if callback
|
||||
|
||||
isRegisteredForURLScheme: (scheme, callback) ->
|
||||
throw new Error "isRegisteredForURLScheme is async, provide a callback" unless callback
|
||||
|
|
|
@ -2,19 +2,27 @@ _ = require 'underscore-plus'
|
|||
proxyquire = require 'proxyquire'
|
||||
|
||||
stubDefaultsJSON = null
|
||||
stubDefaults = null
|
||||
execHitory = []
|
||||
|
||||
ChildProcess =
|
||||
exec: (command, callback) ->
|
||||
console.log(command)
|
||||
execHitory.push(arguments)
|
||||
if command is "defaults read com.apple.launchservices LSHandlers"
|
||||
callback(null, stubDefaults, null)
|
||||
else
|
||||
callback(null, '', null)
|
||||
callback(null, '', null)
|
||||
|
||||
fs =
|
||||
exists: (path, callback) ->
|
||||
callback(true)
|
||||
readFile: (path, callback) ->
|
||||
callback(null, JSON.stringify(stubDefaultsJSON))
|
||||
readFileSync: (path) ->
|
||||
JSON.stringify(stubDefaultsJSON)
|
||||
writeFileSync: (path) ->
|
||||
null
|
||||
|
||||
LaunchServices = proxyquire "../lib/launch-services",
|
||||
"child_process": ChildProcess
|
||||
"child_process": ChildProcess
|
||||
"fs": fs
|
||||
|
||||
describe "LaunchServices", ->
|
||||
beforeEach ->
|
||||
|
@ -109,99 +117,7 @@ describe "LaunchServices", ->
|
|||
LSHandlerURLScheme: 'mailto'
|
||||
}
|
||||
]
|
||||
stubDefaults = """
|
||||
(
|
||||
{
|
||||
LSHandlerRoleAll = "com.apple.dt.xcode";
|
||||
LSHandlerURLScheme = xcdoc;
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.fournova.tower";
|
||||
LSHandlerURLScheme = "github-mac";
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.fournova.tower";
|
||||
LSHandlerURLScheme = sourcetree;
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.google.chrome";
|
||||
LSHandlerURLScheme = http;
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.google.chrome";
|
||||
LSHandlerURLScheme = https;
|
||||
},
|
||||
{
|
||||
LSHandlerContentType = "public.html";
|
||||
LSHandlerRoleViewer = "com.google.chrome";
|
||||
},
|
||||
{
|
||||
LSHandlerContentType = "public.url";
|
||||
LSHandlerRoleViewer = "com.google.chrome";
|
||||
},
|
||||
{
|
||||
LSHandlerContentType = "com.apple.ical.backup";
|
||||
LSHandlerRoleAll = "com.apple.ical";
|
||||
},
|
||||
{
|
||||
LSHandlerContentTag = icalevent;
|
||||
LSHandlerContentTagClass = "public.filename-extension";
|
||||
LSHandlerRoleAll = "com.apple.ical";
|
||||
},
|
||||
{
|
||||
LSHandlerContentTag = icaltodo;
|
||||
LSHandlerContentTagClass = "public.filename-extension";
|
||||
LSHandlerRoleAll = "com.apple.reminders";
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.apple.ical";
|
||||
LSHandlerURLScheme = webcal;
|
||||
},
|
||||
{
|
||||
LSHandlerContentTag = coffee;
|
||||
LSHandlerContentTagClass = "public.filename-extension";
|
||||
LSHandlerRoleAll = "com.sublimetext.2";
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.apple.facetime";
|
||||
LSHandlerURLScheme = facetime;
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.apple.dt.xcode";
|
||||
LSHandlerURLScheme = xcdevice;
|
||||
},
|
||||
{
|
||||
LSHandlerContentType = "public.png";
|
||||
LSHandlerRoleAll = "com.macromedia.fireworks";
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.apple.dt.xcode";
|
||||
LSHandlerURLScheme = xcbot;
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.microsoft.rdc.mac";
|
||||
LSHandlerURLScheme = rdp;
|
||||
},
|
||||
{
|
||||
LSHandlerContentTag = rdp;
|
||||
LSHandlerContentTagClass = "public.filename-extension";
|
||||
LSHandlerRoleAll = "com.microsoft.rdc.mac";
|
||||
},
|
||||
{
|
||||
LSHandlerContentType = "public.json";
|
||||
LSHandlerRoleAll = "com.sublimetext.2";
|
||||
},
|
||||
{
|
||||
LSHandlerContentTag = cson;
|
||||
LSHandlerContentTagClass = "public.filename-extension";
|
||||
LSHandlerRoleAll = "com.sublimetext.2";
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.apple.mail";
|
||||
LSHandlerURLScheme = mailto;
|
||||
}
|
||||
)
|
||||
"""
|
||||
|
||||
|
||||
describe "when the platform is darwin", ->
|
||||
beforeEach ->
|
||||
|
@ -213,118 +129,90 @@ describe "LaunchServices", ->
|
|||
it "should return true", ->
|
||||
expect(@services.available()).toEqual(true)
|
||||
|
||||
describe "pre-Yosemite", ->
|
||||
beforeEach ->
|
||||
@services.isYosemiteOrGreater = (callback) -> callback(false)
|
||||
describe "readDefaults", ->
|
||||
|
||||
describe "readDefaults", ->
|
||||
it "should return the user defaults registered with the system via `defaults`", ->
|
||||
response = null
|
||||
runs ->
|
||||
@services.readDefaults (defaults) ->
|
||||
response = defaults
|
||||
waitsFor ->
|
||||
response
|
||||
runs ->
|
||||
expect(response).toEqual(stubDefaultsJSON)
|
||||
describe "writeDefaults", ->
|
||||
it "should `lsregister` to reload defaults after saving them", ->
|
||||
callback = jasmine.createSpy('callback')
|
||||
@services.writeDefaults(stubDefaultsJSON, callback)
|
||||
callback.callCount is 1
|
||||
command = execHitory[2][0]
|
||||
expect(command).toBe("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user")
|
||||
|
||||
describe "writeDefaults", ->
|
||||
it "should covert the defaults to the plist format and call `defaults write`", ->
|
||||
callback = jasmine.createSpy('callback')
|
||||
@services.writeDefaults(stubDefaultsJSON, callback)
|
||||
command = execHitory[0][0]
|
||||
expect(command).toBe("""defaults write ~/Library/Preferences/com.apple.LaunchServices.plist LSHandlers '({LSHandlerRoleAll = "com.apple.dt.xcode";LSHandlerURLScheme = "xcdoc";},{LSHandlerRoleAll = "com.fournova.tower";LSHandlerURLScheme = "github-mac";},{LSHandlerRoleAll = "com.fournova.tower";LSHandlerURLScheme = "sourcetree";},{LSHandlerRoleAll = "com.google.chrome";LSHandlerURLScheme = "http";},{LSHandlerRoleAll = "com.google.chrome";LSHandlerURLScheme = "https";},{LSHandlerContentType = "public.html";LSHandlerRoleViewer = "com.google.chrome";},{LSHandlerContentType = "public.url";LSHandlerRoleViewer = "com.google.chrome";},{LSHandlerContentType = "com.apple.ical.backup";LSHandlerRoleAll = "com.apple.ical";},{LSHandlerContentTag = "icalevent";LSHandlerContentTagClass = "public.filename-extension";LSHandlerRoleAll = "com.apple.ical";},{LSHandlerContentTag = "icaltodo";LSHandlerContentTagClass = "public.filename-extension";LSHandlerRoleAll = "com.apple.reminders";},{LSHandlerRoleAll = "com.apple.ical";LSHandlerURLScheme = "webcal";},{LSHandlerContentTag = "coffee";LSHandlerContentTagClass = "public.filename-extension";LSHandlerRoleAll = "com.sublimetext.2";},{LSHandlerRoleAll = "com.apple.facetime";LSHandlerURLScheme = "facetime";},{LSHandlerRoleAll = "com.apple.dt.xcode";LSHandlerURLScheme = "xcdevice";},{LSHandlerContentType = "public.png";LSHandlerRoleAll = "com.macromedia.fireworks";},{LSHandlerRoleAll = "com.apple.dt.xcode";LSHandlerURLScheme = "xcbot";},{LSHandlerRoleAll = "com.microsoft.rdc.mac";LSHandlerURLScheme = "rdp";},{LSHandlerContentTag = "rdp";LSHandlerContentTagClass = "public.filename-extension";LSHandlerRoleAll = "com.microsoft.rdc.mac";},{LSHandlerContentType = "public.json";LSHandlerRoleAll = "com.sublimetext.2";},{LSHandlerContentTag = "cson";LSHandlerContentTagClass = "public.filename-extension";LSHandlerRoleAll = "com.sublimetext.2";},{LSHandlerRoleAll = "com.apple.mail";LSHandlerURLScheme = "mailto";})'""")
|
||||
describe "isRegisteredForURLScheme", ->
|
||||
it "should require a callback is provided", ->
|
||||
expect( -> @services.isRegisteredForURLScheme('mailto')).toThrow()
|
||||
|
||||
it "should `lsregister` to reload defaults after saving them", ->
|
||||
callback = jasmine.createSpy('callback')
|
||||
@services.writeDefaults(stubDefaultsJSON, callback)
|
||||
command = execHitory[1][0]
|
||||
expect(command).toBe("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user")
|
||||
it "should return true if a matching `LSHandlerURLScheme` record exists for the bundle identifier", ->
|
||||
spyOn(@services, 'readDefaults').andCallFake (callback) ->
|
||||
callback([{
|
||||
"LSHandlerRoleAll": "com.apple.dt.xcode",
|
||||
"LSHandlerURLScheme": "xcdoc"
|
||||
}, {
|
||||
"LSHandlerContentTag": "cson",
|
||||
"LSHandlerContentTagClass": "public.filename-extension",
|
||||
"LSHandlerRoleAll": "com.sublimetext.2"
|
||||
}, {
|
||||
"LSHandlerRoleAll": "com.inbox.edgehill",
|
||||
"LSHandlerURLScheme": "mailto"
|
||||
}])
|
||||
@services.isRegisteredForURLScheme 'mailto', (registered) ->
|
||||
expect(registered).toBe(true)
|
||||
|
||||
describe "isRegisteredForURLScheme", ->
|
||||
it "should require a callback is provided", ->
|
||||
expect( -> @services.isRegisteredForURLScheme('mailto')).toThrow()
|
||||
it "should return false when other records exist for the bundle identifier but do not match", ->
|
||||
spyOn(@services, 'readDefaults').andCallFake (callback) ->
|
||||
callback([{
|
||||
LSHandlerRoleAll: "com.apple.dt.xcode",
|
||||
LSHandlerURLScheme: "xcdoc"
|
||||
},{
|
||||
LSHandlerContentTag: "cson",
|
||||
LSHandlerContentTagClass: "public.filename-extension",
|
||||
LSHandlerRoleAll: "com.sublimetext.2"
|
||||
},{
|
||||
LSHandlerRoleAll: "com.inbox.edgehill",
|
||||
LSHandlerURLScheme: "atom"
|
||||
}])
|
||||
@services.isRegisteredForURLScheme 'mailto', (registered) ->
|
||||
expect(registered).toBe(false)
|
||||
|
||||
it "should return true if a matching `LSHandlerURLScheme` record exists for the bundle identifier", ->
|
||||
stubDefaults = """
|
||||
(
|
||||
{
|
||||
LSHandlerRoleAll = "com.apple.dt.xcode";
|
||||
LSHandlerURLScheme = xcdoc;
|
||||
},
|
||||
{
|
||||
LSHandlerContentTag = cson;
|
||||
LSHandlerContentTagClass = "public.filename-extension";
|
||||
LSHandlerRoleAll = "com.sublimetext.2";
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.inbox.edgehill";
|
||||
LSHandlerURLScheme = mailto;
|
||||
}
|
||||
)
|
||||
"""
|
||||
@services.isRegisteredForURLScheme 'mailto', (registered) ->
|
||||
expect(registered).toBe(true)
|
||||
it "should return false if another bundle identifier is registered for the `LSHandlerURLScheme`", ->
|
||||
spyOn(@services, 'readDefaults').andCallFake (callback) ->
|
||||
callback([{
|
||||
LSHandlerRoleAll: "com.apple.dt.xcode",
|
||||
LSHandlerURLScheme: "xcdoc"
|
||||
},{
|
||||
LSHandlerContentTag: "cson",
|
||||
LSHandlerContentTagClass: "public.filename-extension",
|
||||
LSHandlerRoleAll: "com.sublimetext.2"
|
||||
},{
|
||||
LSHandlerRoleAll: "com.apple.mail",
|
||||
LSHandlerURLScheme: "mailto"
|
||||
}])
|
||||
@services.isRegisteredForURLScheme 'mailto', (registered) ->
|
||||
expect(registered).toBe(false)
|
||||
|
||||
it "should return false when other records exist for the bundle identifier but do not match", ->
|
||||
stubDefaults = """
|
||||
(
|
||||
{
|
||||
LSHandlerRoleAll = "com.apple.dt.xcode";
|
||||
LSHandlerURLScheme = xcdoc;
|
||||
},
|
||||
{
|
||||
LSHandlerContentTag = cson;
|
||||
LSHandlerContentTagClass = "public.filename-extension";
|
||||
LSHandlerRoleAll = "com.sublimetext.2";
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.inbox.edgehill";
|
||||
LSHandlerURLScheme = atom;
|
||||
}
|
||||
)
|
||||
"""
|
||||
@services.isRegisteredForURLScheme 'mailto', (registered) ->
|
||||
expect(registered).toBe(false)
|
||||
describe "registerForURLScheme", ->
|
||||
it "should remove any existing records for the `LSHandlerURLScheme`", ->
|
||||
@services.registerForURLScheme 'mailto', =>
|
||||
@services.readDefaults (values) ->
|
||||
expect(JSON.stringify(values).indexOf('com.apple.mail')).toBe(-1)
|
||||
|
||||
it "should return false if another bundle identifier is registered for the `LSHandlerURLScheme`", ->
|
||||
stubDefaults = """
|
||||
(
|
||||
{
|
||||
LSHandlerRoleAll = "com.apple.dt.xcode";
|
||||
LSHandlerURLScheme = xcdoc;
|
||||
},
|
||||
{
|
||||
LSHandlerContentTag = cson;
|
||||
LSHandlerContentTagClass = "public.filename-extension";
|
||||
LSHandlerRoleAll = "com.sublimetext.2";
|
||||
},
|
||||
{
|
||||
LSHandlerRoleAll = "com.apple.mail";
|
||||
LSHandlerURLScheme = mailto;
|
||||
}
|
||||
)
|
||||
"""
|
||||
@services.isRegisteredForURLScheme 'mailto', (registered) ->
|
||||
expect(registered).toBe(false)
|
||||
it "should add a record for the `LSHandlerURLScheme` and the app's bundle identifier", ->
|
||||
@services.registerForURLScheme 'mailto', =>
|
||||
@services.readDefaults (defaults) ->
|
||||
match = _.find defaults, (d) ->
|
||||
d.LSHandlerURLScheme is 'mailto' and d.LSHandlerRoleAll is 'com.inbox.edgehill'
|
||||
expect(match).not.toBe(null)
|
||||
|
||||
describe "registerForURLScheme", ->
|
||||
it "should remove any existing records for the `LSHandlerURLScheme`", ->
|
||||
@services.registerForURLScheme 'mailto', =>
|
||||
@services.readDefaults (values) ->
|
||||
expect(JSON.stringify(values).indexOf('com.apple.mail')).toBe(-1)
|
||||
|
||||
it "should add a record for the `LSHandlerURLScheme` and the app's bundle identifier", ->
|
||||
@services.registerForURLScheme 'mailto', =>
|
||||
@services.readDefaults (defaults) ->
|
||||
match = _.find defaults, (d) ->
|
||||
d.LSHandlerURLScheme is 'mailto' and d.LSHandlerRoleAll is 'com.inbox.edgehill'
|
||||
expect(match).not.toBe(null)
|
||||
|
||||
it "should write the new defaults", ->
|
||||
spyOn(@services, 'writeDefaults')
|
||||
@services.registerForURLScheme('mailto')
|
||||
expect(@services.writeDefaults).toHaveBeenCalled()
|
||||
it "should write the new defaults", ->
|
||||
spyOn(@services, 'readDefaults').andCallFake (callback) ->
|
||||
callback([{
|
||||
LSHandlerRoleAll: "com.apple.dt.xcode",
|
||||
LSHandlerURLScheme: "xcdoc"
|
||||
}])
|
||||
spyOn(@services, 'writeDefaults')
|
||||
@services.registerForURLScheme('mailto')
|
||||
expect(@services.writeDefaults).toHaveBeenCalled()
|
||||
|
||||
describe "on other platforms", ->
|
||||
describe "available", ->
|
||||
|
|
Loading…
Reference in a new issue