├── .gitignore ├── LICENSE ├── Podfile ├── README.md ├── XMLHTTPRequest.podspec ├── XMLHTTPRequest.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ ├── XMLHTTPRequest.xcscheme │ └── XMLHTTPRequestTests.xcscheme ├── XMLHTTPRequest.xcworkspace └── contents.xcworkspacedata ├── XMLHTTPRequest ├── Info.plist ├── XMLHTTPRequest.h └── XMLHTTPRequest.m └── XMLHTTPRequestTests ├── Info.plist └── XMLHTTPRequestTests.m /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | *.pbxuser 3 | !default.pbxuser 4 | *.mode1v3 5 | !default.mode1v3 6 | *.mode2v3 7 | !default.mode2v3 8 | *.perspectivev3 9 | !default.perspectivev3 10 | xcuserdata 11 | *.xccheckout 12 | *.moved-aside 13 | DerivedData 14 | *.xcuserstate 15 | .idea/ 16 | 17 | Pods/ 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Lukas Stührk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | target 'XMLHTTPRequestTests' do 4 | pod 'Kiwi', '= 2.4.0' 5 | pod 'OCMockito', '= 1.4.0' 6 | end 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XMLHTTPRequest 2 | 3 | In iOS 7, Apple introduced the possibility to [execute JavaScript via the JavaScriptCore JavaScript 4 | engine] (http://nshipster.com/javascriptcore/). Unfortunately, JavaScriptCore is missing some 5 | objects and functions a JavaScript environment of a browser would have. Especially the 6 | `XMLHttpRequest` (see the [Mozilla documentation] 7 | (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) object needed for AJAX requests 8 | is not provided by JavaScriptCore. This library implements this missing object, so it is possible to 9 | use JavaScript libraries which were originally developed for in-browser use in your Objective-C 10 | (or Swift) application without the need to use a hidden WebView. 11 | 12 | 13 | ## Provided functions 14 | This library tries to implement the full XMLHttpRequest specification. Currently not all 15 | functionality is implemented yet. The current limitations are: 16 | 17 | * Synchronous calls are not supported. 18 | * The `onload` and `onerror` callbacks are currently not supported. 19 | * The `upload` callback is currently not supported. 20 | * The `timeout` property is currently not supported. 21 | 22 | It is planned to support all functionality of the HTML5 specification at some point. 23 | 24 | ## How to use it 25 | Create a new instance of the `XMLHTTPRequest` class. Then call the `extend:` method and pass either 26 | a `JSContext` instance or a `JSValue` instance. The given object will be extend with the 27 | `XMLHTTPRequest` object. 28 | 29 | ```objc 30 | #import 31 | 32 | ... 33 | 34 | JSContext *jsContext = [JSContext new]; 35 | XMLHttpRequest *xmlHttpRequest = [XMLHttpRequest new]; 36 | [xmlHttpRequest extend:jsContext]; 37 | ``` 38 | 39 | The JavaScript context now has a XMLHTTPRequest object you can use like the object found in 40 | browsers. Example (JavaScript): 41 | 42 | ```JavaScript 43 | request.open('GET', 'http://example.com'); 44 | request.setRequestHeader('Accept', 'text/html'); 45 | request.setRequestHeader('X-Foo', 'bar'); 46 | request.send(); 47 | ``` 48 | 49 | ### More Stuff 50 | 51 | If you are interested in more polyfills for missing browser functionality in JavaScriptCore, there is 52 | a window timers implementation (`setTimeout`, `setInterval`, ...) called [WindowTimers] 53 | (https://github.com/Lukas-Stuehrk/WindowTimers). 54 | -------------------------------------------------------------------------------- /XMLHTTPRequest.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "XMLHTTPRequest" 3 | s.version = "0.1.1" 4 | s.summary = "An implementation of the JavaScript XMLHttpRequest object to extend JavaScriptCore." 5 | s.description = <<-DESC 6 | In iOS 7, Apple introduced the possibility to [execute JavaScript via the JavaScriptCore JavaScript 7 | engine] (http://nshipster.com/javascriptcore/). Unfortunately, JavaScriptCore is missing some 8 | objects and functions a JavaScript environment of a browser would have. Especially the 9 | `XMLHTTPRequest` (see the [Mozilla documentation] 10 | (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) object needed for AJAX reqeuests 11 | is not provided by JavaScriptCore. This library implements this missing object, so it is possible to 12 | use JavaScript libraries which were originally developed for in-browser use in your Objective-C 13 | (or Swift) application without the need to use a hidden WebView. 14 | DESC 15 | s.homepage = "https://github.com/Lukas-Stuehrk/XMLHTTPRequest" 16 | s.license = 'MIT' 17 | s.author = { "Lukas Stührk" => "Lukas@Stuehrk.net" } 18 | s.source = { :git => "https://github.com/Lukas-Stuehrk/XMLHTTPRequest.git", :tag => s.version.to_s } 19 | 20 | s.platform = :ios, '7.0' 21 | s.requires_arc = true 22 | 23 | s.source_files = 'XMLHTTPRequest/XMLHTTPRequest.*' 24 | s.resource_bundles = { 25 | } 26 | 27 | s.public_header_files = 'XMLHTTPRequest/XMLHTTPRequest.h' 28 | s.frameworks = 'JavaScriptCore' 29 | end 30 | -------------------------------------------------------------------------------- /XMLHTTPRequest.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 09026FB93013648A3C97B1BC /* libPods-XMLHTTPRequestTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 67E00A49E87A2FE03B5DF4DF /* libPods-XMLHTTPRequestTests.a */; }; 11 | C753E59524925F7BBE9B6D1A /* XMLHTTPRequest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C753EE9E9519D8D16316E93F /* XMLHTTPRequest.framework */; }; 12 | C753E6694DC171979912F19F /* XMLHTTPRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C753EE7475CC18E7BE9D647D /* XMLHTTPRequestTests.m */; }; 13 | C753E69E278966488A99D653 /* XMLHTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = C753E76FA90496EF9536218D /* XMLHTTPRequest.m */; }; 14 | C753EC4B303AF332A70124FD /* Podfile in Resources */ = {isa = PBXBuildFile; fileRef = C753E318ABC43CF4B39FE992 /* Podfile */; }; 15 | C753ED1BB6E6A006A6B54780 /* XMLHTTPRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = C753E59727575EF0571C2816 /* XMLHTTPRequest.h */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXContainerItemProxy section */ 19 | C753EC4AD030F063EF202ADE /* PBXContainerItemProxy */ = { 20 | isa = PBXContainerItemProxy; 21 | containerPortal = C753E8F6CCDF5F32DF2F424E /* Project object */; 22 | proxyType = 1; 23 | remoteGlobalIDString = C753E84E862BDAA2086FDA04; 24 | remoteInfo = XMLHTTPRequest; 25 | }; 26 | /* End PBXContainerItemProxy section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 67E00A49E87A2FE03B5DF4DF /* libPods-XMLHTTPRequestTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-XMLHTTPRequestTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | 81E8F0A2E9F33897800BA0B4 /* Pods-XMLHTTPRequestTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-XMLHTTPRequestTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-XMLHTTPRequestTests/Pods-XMLHTTPRequestTests.debug.xcconfig"; sourceTree = ""; }; 31 | B0B51D21BCF58867BCE0A31C /* Pods-XMLHTTPRequestTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-XMLHTTPRequestTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-XMLHTTPRequestTests/Pods-XMLHTTPRequestTests.release.xcconfig"; sourceTree = ""; }; 32 | C753E15F031EE123B9BC72D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.info; path = Info.plist; sourceTree = ""; }; 33 | C753E318ABC43CF4B39FE992 /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = ""; }; 34 | C753E59727575EF0571C2816 /* XMLHTTPRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XMLHTTPRequest.h; sourceTree = ""; }; 35 | C753E76FA90496EF9536218D /* XMLHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XMLHTTPRequest.m; sourceTree = ""; }; 36 | C753EC01CAF0A777DD8F4024 /* XMLHTTPRequestTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XMLHTTPRequestTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | C753EDECC75F946ACE4B4CC6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.info; path = Info.plist; sourceTree = ""; }; 38 | C753EE7475CC18E7BE9D647D /* XMLHTTPRequestTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XMLHTTPRequestTests.m; sourceTree = ""; }; 39 | C753EE9E9519D8D16316E93F /* XMLHTTPRequest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = XMLHTTPRequest.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | /* End PBXFileReference section */ 41 | 42 | /* Begin PBXFrameworksBuildPhase section */ 43 | C753EC5BCD581523B2686082 /* Frameworks */ = { 44 | isa = PBXFrameworksBuildPhase; 45 | buildActionMask = 2147483647; 46 | files = ( 47 | C753E59524925F7BBE9B6D1A /* XMLHTTPRequest.framework in Frameworks */, 48 | 09026FB93013648A3C97B1BC /* libPods-XMLHTTPRequestTests.a in Frameworks */, 49 | ); 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | C753EF1EF993899D7D0529C2 /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXFrameworksBuildPhase section */ 60 | 61 | /* Begin PBXGroup section */ 62 | 8A05E7E8747ACC580BCFA75B /* Frameworks */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 67E00A49E87A2FE03B5DF4DF /* libPods-XMLHTTPRequestTests.a */, 66 | ); 67 | name = Frameworks; 68 | sourceTree = ""; 69 | }; 70 | C753E057A1C9ECF50D20F882 /* Supporting Files */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | C753E15F031EE123B9BC72D1 /* Info.plist */, 74 | ); 75 | name = "Supporting Files"; 76 | sourceTree = ""; 77 | }; 78 | C753E1F3DCD93D8EEEB6CA0C /* Supporting Files */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | C753EDECC75F946ACE4B4CC6 /* Info.plist */, 82 | ); 83 | name = "Supporting Files"; 84 | sourceTree = ""; 85 | }; 86 | C753E59396DE5515F185544E /* XMLHTTPRequest */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | C753E1F3DCD93D8EEEB6CA0C /* Supporting Files */, 90 | C753E59727575EF0571C2816 /* XMLHTTPRequest.h */, 91 | C753E76FA90496EF9536218D /* XMLHTTPRequest.m */, 92 | ); 93 | path = XMLHTTPRequest; 94 | sourceTree = ""; 95 | }; 96 | C753E64D368B5ADFB52BDBDB /* Products */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | C753EE9E9519D8D16316E93F /* XMLHTTPRequest.framework */, 100 | C753EC01CAF0A777DD8F4024 /* XMLHTTPRequestTests.xctest */, 101 | ); 102 | name = Products; 103 | sourceTree = ""; 104 | }; 105 | C753EB4DC0A936EF7BF1A628 = { 106 | isa = PBXGroup; 107 | children = ( 108 | C753E64D368B5ADFB52BDBDB /* Products */, 109 | C753E59396DE5515F185544E /* XMLHTTPRequest */, 110 | C753ED28519F27797133225F /* XMLHTTPRequestTests */, 111 | C753E318ABC43CF4B39FE992 /* Podfile */, 112 | D16FCF45875058F493B9B22F /* Pods */, 113 | 8A05E7E8747ACC580BCFA75B /* Frameworks */, 114 | ); 115 | sourceTree = ""; 116 | }; 117 | C753ED28519F27797133225F /* XMLHTTPRequestTests */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | C753E057A1C9ECF50D20F882 /* Supporting Files */, 121 | C753EE7475CC18E7BE9D647D /* XMLHTTPRequestTests.m */, 122 | ); 123 | path = XMLHTTPRequestTests; 124 | sourceTree = ""; 125 | }; 126 | D16FCF45875058F493B9B22F /* Pods */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 81E8F0A2E9F33897800BA0B4 /* Pods-XMLHTTPRequestTests.debug.xcconfig */, 130 | B0B51D21BCF58867BCE0A31C /* Pods-XMLHTTPRequestTests.release.xcconfig */, 131 | ); 132 | name = Pods; 133 | sourceTree = ""; 134 | }; 135 | /* End PBXGroup section */ 136 | 137 | /* Begin PBXHeadersBuildPhase section */ 138 | C753E4AC4AEE0EAE256EE0EB /* Headers */ = { 139 | isa = PBXHeadersBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | C753ED1BB6E6A006A6B54780 /* XMLHTTPRequest.h in Headers */, 143 | ); 144 | runOnlyForDeploymentPostprocessing = 0; 145 | }; 146 | /* End PBXHeadersBuildPhase section */ 147 | 148 | /* Begin PBXNativeTarget section */ 149 | C753E84E862BDAA2086FDA04 /* XMLHTTPRequest */ = { 150 | isa = PBXNativeTarget; 151 | buildConfigurationList = C753E047DD390383F7C881AB /* Build configuration list for PBXNativeTarget "XMLHTTPRequest" */; 152 | buildPhases = ( 153 | C753E62AC79EE3E6D90616CC /* Sources */, 154 | C753EF1EF993899D7D0529C2 /* Frameworks */, 155 | C753E4AC4AEE0EAE256EE0EB /* Headers */, 156 | C753E6EAA6163ACBE4B348D8 /* Resources */, 157 | ); 158 | buildRules = ( 159 | ); 160 | dependencies = ( 161 | ); 162 | name = XMLHTTPRequest; 163 | productName = XMLHTTPRequest; 164 | productReference = C753EE9E9519D8D16316E93F /* XMLHTTPRequest.framework */; 165 | productType = "com.apple.product-type.framework"; 166 | }; 167 | C753EB163B9ED73A5A6101E6 /* XMLHTTPRequestTests */ = { 168 | isa = PBXNativeTarget; 169 | buildConfigurationList = C753E94003C4FBBB89D49ABF /* Build configuration list for PBXNativeTarget "XMLHTTPRequestTests" */; 170 | buildPhases = ( 171 | 0A5C0F1CF12FD49AAC4DA2C1 /* [CP] Check Pods Manifest.lock */, 172 | C753E1749E5CEC1C300A20A0 /* Sources */, 173 | C753EC5BCD581523B2686082 /* Frameworks */, 174 | C753E5336ACF3EF5DB0A8103 /* Resources */, 175 | C12B1D8608E97BBCB999E062 /* [CP] Copy Pods Resources */, 176 | DF4BA301CE250C15AB8A159E /* [CP] Embed Pods Frameworks */, 177 | ); 178 | buildRules = ( 179 | ); 180 | dependencies = ( 181 | C753E09998A47C6C9745E2BD /* PBXTargetDependency */, 182 | ); 183 | name = XMLHTTPRequestTests; 184 | productName = XMLHTTPRequestTests; 185 | productReference = C753EC01CAF0A777DD8F4024 /* XMLHTTPRequestTests.xctest */; 186 | productType = "com.apple.product-type.bundle.unit-test"; 187 | }; 188 | /* End PBXNativeTarget section */ 189 | 190 | /* Begin PBXProject section */ 191 | C753E8F6CCDF5F32DF2F424E /* Project object */ = { 192 | isa = PBXProject; 193 | attributes = { 194 | ORGANIZATIONNAME = "Lukas Stührk"; 195 | }; 196 | buildConfigurationList = C753E774A178C907808F341F /* Build configuration list for PBXProject "XMLHTTPRequest" */; 197 | compatibilityVersion = "Xcode 3.2"; 198 | developmentRegion = English; 199 | hasScannedForEncodings = 0; 200 | knownRegions = ( 201 | en, 202 | ); 203 | mainGroup = C753EB4DC0A936EF7BF1A628; 204 | productRefGroup = C753E64D368B5ADFB52BDBDB /* Products */; 205 | projectDirPath = ""; 206 | projectRoot = ""; 207 | targets = ( 208 | C753E84E862BDAA2086FDA04 /* XMLHTTPRequest */, 209 | C753EB163B9ED73A5A6101E6 /* XMLHTTPRequestTests */, 210 | ); 211 | }; 212 | /* End PBXProject section */ 213 | 214 | /* Begin PBXResourcesBuildPhase section */ 215 | C753E5336ACF3EF5DB0A8103 /* Resources */ = { 216 | isa = PBXResourcesBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | C753E6EAA6163ACBE4B348D8 /* Resources */ = { 223 | isa = PBXResourcesBuildPhase; 224 | buildActionMask = 2147483647; 225 | files = ( 226 | C753EC4B303AF332A70124FD /* Podfile in Resources */, 227 | ); 228 | runOnlyForDeploymentPostprocessing = 0; 229 | }; 230 | /* End PBXResourcesBuildPhase section */ 231 | 232 | /* Begin PBXShellScriptBuildPhase section */ 233 | 0A5C0F1CF12FD49AAC4DA2C1 /* [CP] Check Pods Manifest.lock */ = { 234 | isa = PBXShellScriptBuildPhase; 235 | buildActionMask = 2147483647; 236 | files = ( 237 | ); 238 | inputPaths = ( 239 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 240 | "${PODS_ROOT}/Manifest.lock", 241 | ); 242 | name = "[CP] Check Pods Manifest.lock"; 243 | outputPaths = ( 244 | "$(DERIVED_FILE_DIR)/Pods-XMLHTTPRequestTests-checkManifestLockResult.txt", 245 | ); 246 | runOnlyForDeploymentPostprocessing = 0; 247 | shellPath = /bin/sh; 248 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 249 | showEnvVarsInLog = 0; 250 | }; 251 | C12B1D8608E97BBCB999E062 /* [CP] Copy Pods Resources */ = { 252 | isa = PBXShellScriptBuildPhase; 253 | buildActionMask = 2147483647; 254 | files = ( 255 | ); 256 | inputPaths = ( 257 | ); 258 | name = "[CP] Copy Pods Resources"; 259 | outputPaths = ( 260 | ); 261 | runOnlyForDeploymentPostprocessing = 0; 262 | shellPath = /bin/sh; 263 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-XMLHTTPRequestTests/Pods-XMLHTTPRequestTests-resources.sh\"\n"; 264 | showEnvVarsInLog = 0; 265 | }; 266 | DF4BA301CE250C15AB8A159E /* [CP] Embed Pods Frameworks */ = { 267 | isa = PBXShellScriptBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | ); 271 | inputPaths = ( 272 | ); 273 | name = "[CP] Embed Pods Frameworks"; 274 | outputPaths = ( 275 | ); 276 | runOnlyForDeploymentPostprocessing = 0; 277 | shellPath = /bin/sh; 278 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-XMLHTTPRequestTests/Pods-XMLHTTPRequestTests-frameworks.sh\"\n"; 279 | showEnvVarsInLog = 0; 280 | }; 281 | /* End PBXShellScriptBuildPhase section */ 282 | 283 | /* Begin PBXSourcesBuildPhase section */ 284 | C753E1749E5CEC1C300A20A0 /* Sources */ = { 285 | isa = PBXSourcesBuildPhase; 286 | buildActionMask = 2147483647; 287 | files = ( 288 | C753E6694DC171979912F19F /* XMLHTTPRequestTests.m in Sources */, 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | C753E62AC79EE3E6D90616CC /* Sources */ = { 293 | isa = PBXSourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | C753E69E278966488A99D653 /* XMLHTTPRequest.m in Sources */, 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | }; 300 | /* End PBXSourcesBuildPhase section */ 301 | 302 | /* Begin PBXTargetDependency section */ 303 | C753E09998A47C6C9745E2BD /* PBXTargetDependency */ = { 304 | isa = PBXTargetDependency; 305 | target = C753E84E862BDAA2086FDA04 /* XMLHTTPRequest */; 306 | targetProxy = C753EC4AD030F063EF202ADE /* PBXContainerItemProxy */; 307 | }; 308 | /* End PBXTargetDependency section */ 309 | 310 | /* Begin XCBuildConfiguration section */ 311 | C753E0C3E8C70BA1617F754C /* Debug */ = { 312 | isa = XCBuildConfiguration; 313 | baseConfigurationReference = 81E8F0A2E9F33897800BA0B4 /* Pods-XMLHTTPRequestTests.debug.xcconfig */; 314 | buildSettings = { 315 | FRAMEWORK_SEARCH_PATHS = ( 316 | "$(SDKROOT)/Developer/Library/Frameworks", 317 | "$(inherited)", 318 | ); 319 | INFOPLIST_FILE = XMLHTTPRequestTests/Info.plist; 320 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 321 | PRODUCT_NAME = "$(TARGET_NAME)"; 322 | }; 323 | name = Debug; 324 | }; 325 | C753E15F7B0EBAD2626E8102 /* Debug */ = { 326 | isa = XCBuildConfiguration; 327 | buildSettings = { 328 | ALWAYS_SEARCH_USER_PATHS = NO; 329 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 330 | CLANG_CXX_LIBRARY = "libc++"; 331 | CLANG_ENABLE_MODULES = YES; 332 | CLANG_ENABLE_OBJC_ARC = YES; 333 | CLANG_WARN_BOOL_CONVERSION = YES; 334 | CLANG_WARN_CONSTANT_CONVERSION = YES; 335 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 336 | CLANG_WARN_EMPTY_BODY = YES; 337 | CLANG_WARN_ENUM_CONVERSION = YES; 338 | CLANG_WARN_INT_CONVERSION = YES; 339 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 340 | CLANG_WARN_UNREACHABLE_CODE = YES; 341 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 342 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 343 | COPY_PHASE_STRIP = NO; 344 | CURRENT_PROJECT_VERSION = 1; 345 | ENABLE_STRICT_OBJC_MSGSEND = YES; 346 | GCC_C_LANGUAGE_STANDARD = gnu99; 347 | GCC_DYNAMIC_NO_PIC = NO; 348 | GCC_OPTIMIZATION_LEVEL = 0; 349 | GCC_PREPROCESSOR_DEFINITIONS = ( 350 | "DEBUG=1", 351 | "$(inherited)", 352 | ); 353 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 354 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 355 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 356 | GCC_WARN_UNDECLARED_SELECTOR = YES; 357 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 358 | GCC_WARN_UNUSED_FUNCTION = YES; 359 | GCC_WARN_UNUSED_VARIABLE = YES; 360 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 361 | MTL_ENABLE_DEBUG_INFO = YES; 362 | ONLY_ACTIVE_ARCH = YES; 363 | SDKROOT = iphoneos; 364 | TARGETED_DEVICE_FAMILY = "1,2"; 365 | VERSIONING_SYSTEM = "apple-generic"; 366 | VERSION_INFO_PREFIX = ""; 367 | }; 368 | name = Debug; 369 | }; 370 | C753E577C06AAE58FD78133E /* Release */ = { 371 | isa = XCBuildConfiguration; 372 | baseConfigurationReference = B0B51D21BCF58867BCE0A31C /* Pods-XMLHTTPRequestTests.release.xcconfig */; 373 | buildSettings = { 374 | FRAMEWORK_SEARCH_PATHS = ( 375 | "$(SDKROOT)/Developer/Library/Frameworks", 376 | "$(inherited)", 377 | ); 378 | INFOPLIST_FILE = XMLHTTPRequestTests/Info.plist; 379 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 380 | PRODUCT_NAME = "$(TARGET_NAME)"; 381 | }; 382 | name = Release; 383 | }; 384 | C753E6D36647630470CC7BD9 /* Debug */ = { 385 | isa = XCBuildConfiguration; 386 | buildSettings = { 387 | DEFINES_MODULE = YES; 388 | DYLIB_COMPATIBILITY_VERSION = 1; 389 | DYLIB_CURRENT_VERSION = 1; 390 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 391 | INFOPLIST_FILE = XMLHTTPRequest/Info.plist; 392 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 393 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 394 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 395 | PRODUCT_NAME = "$(TARGET_NAME)"; 396 | SKIP_INSTALL = YES; 397 | }; 398 | name = Debug; 399 | }; 400 | C753E820B1184DB45364A7AE /* Release */ = { 401 | isa = XCBuildConfiguration; 402 | buildSettings = { 403 | ALWAYS_SEARCH_USER_PATHS = NO; 404 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 405 | CLANG_CXX_LIBRARY = "libc++"; 406 | CLANG_ENABLE_MODULES = YES; 407 | CLANG_ENABLE_OBJC_ARC = YES; 408 | CLANG_WARN_BOOL_CONVERSION = YES; 409 | CLANG_WARN_CONSTANT_CONVERSION = YES; 410 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 411 | CLANG_WARN_EMPTY_BODY = YES; 412 | CLANG_WARN_ENUM_CONVERSION = YES; 413 | CLANG_WARN_INT_CONVERSION = YES; 414 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 415 | CLANG_WARN_UNREACHABLE_CODE = YES; 416 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 417 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 418 | COPY_PHASE_STRIP = YES; 419 | CURRENT_PROJECT_VERSION = 1; 420 | ENABLE_NS_ASSERTIONS = NO; 421 | ENABLE_STRICT_OBJC_MSGSEND = YES; 422 | GCC_C_LANGUAGE_STANDARD = gnu99; 423 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 424 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 425 | GCC_WARN_UNDECLARED_SELECTOR = YES; 426 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 427 | GCC_WARN_UNUSED_FUNCTION = YES; 428 | GCC_WARN_UNUSED_VARIABLE = YES; 429 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 430 | MTL_ENABLE_DEBUG_INFO = NO; 431 | SDKROOT = iphoneos; 432 | TARGETED_DEVICE_FAMILY = "1,2"; 433 | VALIDATE_PRODUCT = YES; 434 | VERSIONING_SYSTEM = "apple-generic"; 435 | VERSION_INFO_PREFIX = ""; 436 | }; 437 | name = Release; 438 | }; 439 | C753EC838296EDA0140E551C /* Release */ = { 440 | isa = XCBuildConfiguration; 441 | buildSettings = { 442 | DEFINES_MODULE = YES; 443 | DYLIB_COMPATIBILITY_VERSION = 1; 444 | DYLIB_CURRENT_VERSION = 1; 445 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 446 | INFOPLIST_FILE = XMLHTTPRequest/Info.plist; 447 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 448 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 449 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 450 | PRODUCT_NAME = "$(TARGET_NAME)"; 451 | SKIP_INSTALL = YES; 452 | }; 453 | name = Release; 454 | }; 455 | /* End XCBuildConfiguration section */ 456 | 457 | /* Begin XCConfigurationList section */ 458 | C753E047DD390383F7C881AB /* Build configuration list for PBXNativeTarget "XMLHTTPRequest" */ = { 459 | isa = XCConfigurationList; 460 | buildConfigurations = ( 461 | C753E6D36647630470CC7BD9 /* Debug */, 462 | C753EC838296EDA0140E551C /* Release */, 463 | ); 464 | defaultConfigurationIsVisible = 0; 465 | defaultConfigurationName = Release; 466 | }; 467 | C753E774A178C907808F341F /* Build configuration list for PBXProject "XMLHTTPRequest" */ = { 468 | isa = XCConfigurationList; 469 | buildConfigurations = ( 470 | C753E15F7B0EBAD2626E8102 /* Debug */, 471 | C753E820B1184DB45364A7AE /* Release */, 472 | ); 473 | defaultConfigurationIsVisible = 0; 474 | defaultConfigurationName = Release; 475 | }; 476 | C753E94003C4FBBB89D49ABF /* Build configuration list for PBXNativeTarget "XMLHTTPRequestTests" */ = { 477 | isa = XCConfigurationList; 478 | buildConfigurations = ( 479 | C753E0C3E8C70BA1617F754C /* Debug */, 480 | C753E577C06AAE58FD78133E /* Release */, 481 | ); 482 | defaultConfigurationIsVisible = 0; 483 | defaultConfigurationName = Release; 484 | }; 485 | /* End XCConfigurationList section */ 486 | }; 487 | rootObject = C753E8F6CCDF5F32DF2F424E /* Project object */; 488 | } 489 | -------------------------------------------------------------------------------- /XMLHTTPRequest.xcodeproj/xcshareddata/xcschemes/XMLHTTPRequest.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /XMLHTTPRequest.xcodeproj/xcshareddata/xcschemes/XMLHTTPRequestTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /XMLHTTPRequest.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /XMLHTTPRequest/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CFBundleIdentifier 7 | net.stuehrk.lukas.$(PRODUCT_NAME:rfc1034identifier) 8 | CFBundleInfoDictionaryVersion 9 | 6.0 10 | CFBundleSignature 11 | ???? 12 | 13 | CFBundleExecutable 14 | $(EXECUTABLE_NAME) 15 | 16 | CFBundleName 17 | $(PRODUCT_NAME) 18 | 19 | CFBundleDevelopmentRegion 20 | en 21 | 22 | CFBundleVersion 23 | $(CURRENT_PROJECT_VERSION) 24 | CFBundleShortVersionString 25 | 1.0 26 | 27 | CFBundlePackageType 28 | FMWK 29 | NSPrincipalClass 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /XMLHTTPRequest/XMLHTTPRequest.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | 6 | typedef NS_ENUM(NSUInteger , ReadyState) { 7 | XMLHttpRequestUNSENT =0, // open()has not been called yet. 8 | XMLHttpRequestOPENED, // send()has not been called yet. 9 | XMLHttpRequestHEADERS, // RECEIVED send() has been called, and headers and status are available. 10 | XMLHttpRequestLOADING, // Downloading; responseText holds partial data. 11 | XMLHttpRequestDONE // The operation is complete. 12 | }; 13 | 14 | @protocol XMLHttpRequest 15 | @property (nonatomic) NSString *response; 16 | @property (nonatomic) NSString *responseText; 17 | @property (nonatomic) NSString *responseType; 18 | @property (nonatomic) JSValue *onreadystatechange; 19 | @property (nonatomic) NSNumber *readyState; 20 | @property (nonatomic) JSValue *onload; 21 | @property (nonatomic) JSValue *onerror; 22 | @property (nonatomic) NSNumber *status; 23 | @property (nonatomic) NSString *statusText; 24 | 25 | 26 | -(void)open:(NSString *)httpMethod :(NSString *)url :(bool)async; 27 | -(void)send:(id)data; 28 | -(void)setRequestHeader: (NSString *)name :(NSString *)value; 29 | -(NSString *)getAllResponseHeaders; 30 | -(NSString *)getResponseHeader:(NSString *)name; 31 | 32 | @end 33 | 34 | 35 | 36 | @interface XMLHttpRequest : NSObject 37 | 38 | - (instancetype)initWithURLSession: (NSURLSession *)urlSession; 39 | 40 | - (void)extend:(id)jsContext; 41 | @end 42 | -------------------------------------------------------------------------------- /XMLHTTPRequest/XMLHTTPRequest.m: -------------------------------------------------------------------------------- 1 | #import "XMLHTTPRequest.h" 2 | 3 | 4 | @implementation XMLHttpRequest { 5 | NSURLSession *_urlSession; 6 | NSString *_httpMethod; 7 | NSURL *_url; 8 | bool _async; 9 | NSMutableDictionary *_requestHeaders; 10 | NSDictionary *_responseHeaders; 11 | }; 12 | 13 | @synthesize response; 14 | @synthesize responseText; 15 | @synthesize responseType; 16 | @synthesize onreadystatechange; 17 | @synthesize readyState; 18 | @synthesize onload; 19 | @synthesize onerror; 20 | @synthesize status; 21 | @synthesize statusText; 22 | 23 | 24 | - (instancetype)init { 25 | return [self initWithURLSession:[NSURLSession sharedSession]]; 26 | } 27 | 28 | 29 | - (instancetype)initWithURLSession:(NSURLSession *)urlSession { 30 | if (self = [super init]) { 31 | _urlSession = urlSession; 32 | self.readyState = @(XMLHttpRequestUNSENT); 33 | _requestHeaders = [NSMutableDictionary new]; 34 | } 35 | return self; 36 | } 37 | 38 | - (void)extend:(id)jsContext { 39 | 40 | // Simulate the constructor. 41 | jsContext[@"XMLHttpRequest"] = ^{ 42 | return self; 43 | }; 44 | jsContext[@"XMLHttpRequest"][@"UNSENT"] = @(XMLHttpRequestUNSENT); 45 | jsContext[@"XMLHttpRequest"][@"OPENED"] = @(XMLHttpRequestOPENED); 46 | jsContext[@"XMLHttpRequest"][@"LOADING"] = @(XMLHttpRequestLOADING); 47 | jsContext[@"XMLHttpRequest"][@"HEADERS"] = @(XMLHttpRequestHEADERS); 48 | jsContext[@"XMLHttpRequest"][@"DONE"] = @(XMLHttpRequestDONE); 49 | 50 | } 51 | 52 | - (void)open:(NSString *)httpMethod :(NSString *)url :(bool)async { 53 | // TODO should throw an error if called with wrong arguments 54 | _httpMethod = httpMethod; 55 | _url = [NSURL URLWithString:url]; 56 | _async = async; 57 | self.readyState = @(XMLHttpRequestOPENED); 58 | } 59 | 60 | - (void)send:(id)data { 61 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_url]; 62 | for (NSString *name in _requestHeaders) { 63 | [request setValue:_requestHeaders[name] forHTTPHeaderField:name]; 64 | } 65 | if ([data isKindOfClass:[NSString class]]) { 66 | request.HTTPBody = [((NSString *) data) dataUsingEncoding:NSUTF8StringEncoding]; 67 | } 68 | [request setHTTPMethod:_httpMethod]; 69 | 70 | __block __weak XMLHttpRequest *weakSelf = self; 71 | 72 | id completionHandler = ^(NSData *receivedData, NSURLResponse *response, NSError *error) { 73 | NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response; 74 | weakSelf.readyState = @(XMLHttpRequestDONE); // TODO 75 | weakSelf.status = @(httpResponse.statusCode); 76 | weakSelf.statusText = [NSString stringWithFormat:@"%ld",httpResponse.statusCode]; 77 | weakSelf.responseText = [[NSString alloc] initWithData:receivedData 78 | encoding:NSUTF8StringEncoding]; 79 | 80 | weakSelf.responseType = @""; 81 | weakSelf.response = weakSelf.responseText; 82 | 83 | [weakSelf setAllResponseHeaders:[httpResponse allHeaderFields]]; 84 | if (weakSelf.onreadystatechange != nil) { 85 | [weakSelf.onreadystatechange callWithArguments:@[]]; 86 | } 87 | }; 88 | NSURLSessionDataTask *task = [_urlSession dataTaskWithRequest:request 89 | completionHandler:completionHandler]; 90 | [task resume]; 91 | } 92 | 93 | - (void)setRequestHeader:(NSString *)name :(NSString *)value { 94 | _requestHeaders[name] = value; 95 | } 96 | 97 | - (NSString *)getAllResponseHeaders { 98 | NSMutableString *responseHeaders = [NSMutableString new]; 99 | for (NSString *key in _responseHeaders) { 100 | [responseHeaders appendString:key]; 101 | [responseHeaders appendString:@": "]; 102 | [responseHeaders appendString:_responseHeaders[key]]; 103 | [responseHeaders appendString:@"\r\n"]; 104 | } 105 | return responseHeaders; 106 | } 107 | 108 | - (NSString *)getResponseHeader:(NSString *)name { 109 | return _responseHeaders[name]; 110 | } 111 | 112 | - (void)setAllResponseHeaders:(NSDictionary *)responseHeaders { 113 | _responseHeaders = responseHeaders; 114 | } 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /XMLHTTPRequestTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CFBundleIdentifier 7 | net.stuehrk.lukas.$(PRODUCT_NAME:rfc1034identifier) 8 | CFBundleInfoDictionaryVersion 9 | 6.0 10 | CFBundleSignature 11 | ???? 12 | 13 | CFBundleExecutable 14 | $(EXECUTABLE_NAME) 15 | 16 | CFBundleName 17 | $(PRODUCT_NAME) 18 | 19 | CFBundleDevelopmentRegion 20 | en 21 | 22 | CFBundleShortVersionString 23 | 1.0 24 | CFBundleVersion 25 | 1 26 | 27 | CFBundlePackageType 28 | BNDL 29 | 30 | 31 | -------------------------------------------------------------------------------- /XMLHTTPRequestTests/XMLHTTPRequestTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #define HC_SHORTHAND 4 | 5 | #import 6 | 7 | #define MOCKITO_SHORTHAND 8 | 9 | #import 10 | #import "XMLHTTPRequest.h" 11 | 12 | 13 | SPEC_BEGIN(XMLHttpRequestTests) 14 | 15 | describe(@"the XMLHTTPRequest", ^{ 16 | __block JSContext *jsContext; 17 | 18 | beforeEach(^{ 19 | jsContext = [JSContext new]; 20 | XMLHttpRequest *xmlHttpRequest = [XMLHttpRequest new]; 21 | [xmlHttpRequest extend:jsContext]; 22 | }); 23 | 24 | it(@"should be a constructor", ^{ 25 | JSValue *object = [jsContext evaluateScript:@"new XMLHttpRequest()"]; 26 | [[[jsContext exception] should] beNil]; 27 | [[object should] beNonNil]; 28 | }); 29 | 30 | it(@"should provide all the constants", ^{ 31 | [[[jsContext evaluateScript:@"XMLHttpRequest.UNSENT"] should] equal:[JSValue valueWithInt32:0 32 | inContext:jsContext]]; 33 | [[[jsContext evaluateScript:@"XMLHttpRequest.OPENED"] should] equal:[JSValue valueWithInt32:1 34 | inContext:jsContext]]; 35 | [[[jsContext evaluateScript:@"XMLHttpRequest.HEADERS"] should] equal:[JSValue valueWithInt32:2 36 | inContext:jsContext]]; 37 | [[[jsContext evaluateScript:@"XMLHttpRequest.LOADING"] should] equal:[JSValue valueWithInt32:3 38 | inContext:jsContext]]; 39 | [[[jsContext evaluateScript:@"XMLHttpRequest.DONE"] should] equal:[JSValue valueWithInt32:4 40 | inContext:jsContext]]; 41 | 42 | }); 43 | }); 44 | 45 | describe(@"the open method", ^{ 46 | __block JSContext *jsContext; 47 | 48 | beforeEach(^{ 49 | jsContext = [JSContext new]; 50 | XMLHttpRequest *xmlHttpRequest = [XMLHttpRequest new]; 51 | [xmlHttpRequest extend:jsContext]; 52 | [jsContext evaluateScript:@"var request = new XMLHttpRequest();"]; 53 | }); 54 | 55 | it(@"should exist", ^{ 56 | [jsContext evaluateScript:@"request.open('POST', 'http://google.de');"]; 57 | [[[jsContext exception] should] beNil]; 58 | }); 59 | 60 | it(@"should raise an error if called with not enough arguments", ^{ 61 | [jsContext evaluateScript:@"request.open()"]; 62 | [[[jsContext exception] should] beNonNil]; 63 | [jsContext evaluateScript:@"request.open('POST')"]; 64 | [[[jsContext exception] should] beNonNil]; 65 | }); 66 | 67 | }); 68 | 69 | describe(@"the request", ^{ 70 | __block JSContext *jsContext; 71 | __block NSURLSession *urlSession; 72 | __block XMLHttpRequest *request; 73 | 74 | beforeEach(^{ 75 | urlSession = mock([NSURLSession class]); 76 | jsContext = [JSContext new]; 77 | XMLHttpRequest *xmlHttpRequest = [[XMLHttpRequest alloc] initWithURLSession:urlSession]; 78 | [xmlHttpRequest extend:jsContext]; 79 | [jsContext evaluateScript:@"var request = new XMLHttpRequest();"]; 80 | request = [jsContext[@"request"] toObject]; 81 | }); 82 | 83 | it(@"should call the correct URL", ^{ 84 | MKTArgumentCaptor *argument = [MKTArgumentCaptor new]; 85 | 86 | [jsContext evaluateScript:@"" 87 | "request.open('GET', 'http://example.com');" 88 | "request.send();"]; 89 | 90 | [verify(urlSession) dataTaskWithRequest:[argument capture] 91 | completionHandler:anything()]; 92 | NSMutableURLRequest *urlRequest = argument.value; 93 | [[[urlRequest URL] should] equal:[NSURL URLWithString:@"http://example.com"]]; 94 | }); 95 | 96 | it(@"should set the correct headers", ^{ 97 | MKTArgumentCaptor *argument = [MKTArgumentCaptor new]; 98 | 99 | [jsContext evaluateScript:@"" 100 | "request.open('GET', 'http://example.com');" 101 | "request.setRequestHeader('Accept', 'text/html');" 102 | "request.setRequestHeader('X-Foo', 'bar');" 103 | "request.send();"]; 104 | 105 | [verify(urlSession) dataTaskWithRequest:[argument capture] 106 | completionHandler:anything()]; 107 | NSMutableURLRequest *urlRequest = argument.value; 108 | [[[urlRequest allHTTPHeaderFields] should] equal:@{@"Accept" : @"text/html", @"X-Foo" : @"bar"}]; 109 | }); 110 | 111 | it(@"should set the correct readystate", ^{ 112 | MKTArgumentCaptor *argument = [MKTArgumentCaptor new]; 113 | [[request.readyState should] equal:@(XMLHttpRequestUNSENT)]; 114 | [jsContext evaluateScript:@"request.open('GET', 'http://example.com');"]; 115 | [[request.readyState should] equal:@(XMLHttpRequestOPENED)]; 116 | [jsContext evaluateScript:@"request.send()"]; 117 | [verify(urlSession) dataTaskWithRequest:anything() 118 | completionHandler:[argument capture]]; 119 | NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"http://example.com"] 120 | statusCode:200 121 | HTTPVersion:@"1.1" 122 | headerFields:@{}]; 123 | void (^completionBlock)(NSData *, NSURLResponse *, NSError *) = [argument value]; 124 | completionBlock([NSData new], response, nil); 125 | [[request.readyState should] equal:@(XMLHttpRequestDONE)]; 126 | }); 127 | 128 | it(@"should set the correct response text", ^{ 129 | MKTArgumentCaptor *argument = [MKTArgumentCaptor new]; 130 | [jsContext evaluateScript:@"request.open('GET', 'http://example.com');"]; 131 | [jsContext evaluateScript:@"request.send()"]; 132 | [verify(urlSession) dataTaskWithRequest:anything() 133 | completionHandler:[argument capture]]; 134 | NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"http://example.com"] 135 | statusCode:200 136 | HTTPVersion:@"1.1" 137 | headerFields:@{}]; 138 | NSData *responseText = [@"foobar" dataUsingEncoding:NSUTF8StringEncoding]; 139 | void (^completionBlock)(NSData *, NSURLResponse *, NSError *) = [argument value]; 140 | completionBlock(responseText, response, nil); 141 | [[request.responseText should] equal:@"foobar"]; 142 | }); 143 | 144 | it(@"should return all response headers", ^{ 145 | MKTArgumentCaptor *argument = [MKTArgumentCaptor new]; 146 | [jsContext evaluateScript:@"request.open('GET', 'http://example.com');"]; 147 | [jsContext evaluateScript:@"request.send()"]; 148 | [verify(urlSession) dataTaskWithRequest:anything() 149 | completionHandler:[argument capture]]; 150 | NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"http://example.com"] 151 | statusCode:200 152 | HTTPVersion:@"1.1" 153 | headerFields:@{@"Content-Type" : @"text/html", @"X-Foo" : @"Bar"}]; 154 | NSData *responseText = [@"foobar" dataUsingEncoding:NSUTF8StringEncoding]; 155 | void (^completionBlock)(NSData *, NSURLResponse *, NSError *) = [argument value]; 156 | completionBlock(responseText, response, nil); 157 | // TODO it's a little bit fragile 158 | [[request.getAllResponseHeaders should] equal:@"X-Foo: Bar\r\nContent-Type: text/html\r\n"]; 159 | }); 160 | 161 | it(@"should return the correct response headers", ^{ 162 | MKTArgumentCaptor *argument = [MKTArgumentCaptor new]; 163 | [jsContext evaluateScript:@"request.open('GET', 'http://example.com');"]; 164 | [jsContext evaluateScript:@"request.send()"]; 165 | [verify(urlSession) dataTaskWithRequest:anything() 166 | completionHandler:[argument capture]]; 167 | NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"http://example.com"] 168 | statusCode:200 169 | HTTPVersion:@"1.1" 170 | headerFields:@{@"Content-Type" : @"text/html", @"X-Foo" : @"Bar"}]; 171 | NSData *responseText = [@"foobar" dataUsingEncoding:NSUTF8StringEncoding]; 172 | void (^completionBlock)(NSData *, NSURLResponse *, NSError *) = [argument value]; 173 | completionBlock(responseText, response, nil); 174 | 175 | [[[[jsContext evaluateScript:@"request.getResponseHeader('Content-Type');"] toString] should] equal:@"text/html"]; 176 | }); 177 | 178 | it(@"should set the HTTP status code", ^{ 179 | MKTArgumentCaptor *argument = [MKTArgumentCaptor new]; 180 | [jsContext evaluateScript:@"request.open('GET', 'http://example.com');"]; 181 | [jsContext evaluateScript:@"request.send()"]; 182 | [verify(urlSession) dataTaskWithRequest:anything() 183 | completionHandler:[argument capture]]; 184 | NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"http://example.com"] 185 | statusCode:200 186 | HTTPVersion:@"1.1" 187 | headerFields:@{}]; 188 | NSData *responseText = [@"foobar" dataUsingEncoding:NSUTF8StringEncoding]; 189 | void (^completionBlock)(NSData *, NSURLResponse *, NSError *) = [argument value]; 190 | completionBlock(responseText, response, nil); 191 | [[request.status should] equal:@(200)]; 192 | }); 193 | }); 194 | 195 | SPEC_END 196 | --------------------------------------------------------------------------------