1<?php 2 3namespace React\Promise\PromiseTest; 4 5use React\Promise; 6use React\Promise\Deferred; 7 8trait RejectTestTrait 9{ 10 /** 11 * @return \React\Promise\PromiseAdapter\PromiseAdapterInterface 12 */ 13 abstract public function getPromiseTestAdapter(callable $canceller = null); 14 15 /** @test */ 16 public function rejectShouldRejectWithAnImmediateValue() 17 { 18 $adapter = $this->getPromiseTestAdapter(); 19 20 $mock = $this->createCallableMock(); 21 $mock 22 ->expects($this->once()) 23 ->method('__invoke') 24 ->with($this->identicalTo(1)); 25 26 $adapter->promise() 27 ->then($this->expectCallableNever(), $mock); 28 29 $adapter->reject(1); 30 } 31 32 /** @test */ 33 public function rejectShouldRejectWithFulfilledPromise() 34 { 35 $adapter = $this->getPromiseTestAdapter(); 36 37 $mock = $this->createCallableMock(); 38 $mock 39 ->expects($this->once()) 40 ->method('__invoke') 41 ->with($this->identicalTo(1)); 42 43 $adapter->promise() 44 ->then($this->expectCallableNever(), $mock); 45 46 $adapter->reject(Promise\resolve(1)); 47 } 48 49 /** @test */ 50 public function rejectShouldRejectWithRejectedPromise() 51 { 52 $adapter = $this->getPromiseTestAdapter(); 53 54 $mock = $this->createCallableMock(); 55 $mock 56 ->expects($this->once()) 57 ->method('__invoke') 58 ->with($this->identicalTo(1)); 59 60 $adapter->promise() 61 ->then($this->expectCallableNever(), $mock); 62 63 $adapter->reject(Promise\reject(1)); 64 } 65 66 /** @test */ 67 public function rejectShouldForwardReasonWhenCallbackIsNull() 68 { 69 $adapter = $this->getPromiseTestAdapter(); 70 71 $mock = $this->createCallableMock(); 72 $mock 73 ->expects($this->once()) 74 ->method('__invoke') 75 ->with($this->identicalTo(1)); 76 77 $adapter->promise() 78 ->then( 79 $this->expectCallableNever() 80 ) 81 ->then( 82 $this->expectCallableNever(), 83 $mock 84 ); 85 86 $adapter->reject(1); 87 } 88 89 /** @test */ 90 public function rejectShouldMakePromiseImmutable() 91 { 92 $adapter = $this->getPromiseTestAdapter(); 93 94 $mock = $this->createCallableMock(); 95 $mock 96 ->expects($this->once()) 97 ->method('__invoke') 98 ->with($this->identicalTo(1)); 99 100 $adapter->promise() 101 ->then(null, function ($value) use ($adapter) { 102 $adapter->reject(3); 103 104 return Promise\reject($value); 105 }) 106 ->then( 107 $this->expectCallableNever(), 108 $mock 109 ); 110 111 $adapter->reject(1); 112 $adapter->reject(2); 113 } 114 115 /** @test */ 116 public function notifyShouldInvokeOtherwiseHandler() 117 { 118 $adapter = $this->getPromiseTestAdapter(); 119 120 $mock = $this->createCallableMock(); 121 $mock 122 ->expects($this->once()) 123 ->method('__invoke') 124 ->with($this->identicalTo(1)); 125 126 $adapter->promise() 127 ->otherwise($mock); 128 129 $adapter->reject(1); 130 } 131 132 /** @test */ 133 public function doneShouldInvokeRejectionHandler() 134 { 135 $adapter = $this->getPromiseTestAdapter(); 136 137 $mock = $this->createCallableMock(); 138 $mock 139 ->expects($this->once()) 140 ->method('__invoke') 141 ->with($this->identicalTo(1)); 142 143 $this->assertNull($adapter->promise()->done(null, $mock)); 144 $adapter->reject(1); 145 } 146 147 /** @test */ 148 public function doneShouldThrowExceptionThrownByRejectionHandler() 149 { 150 $adapter = $this->getPromiseTestAdapter(); 151 152 $this->setExpectedException('\Exception', 'UnhandledRejectionException'); 153 154 $this->assertNull($adapter->promise()->done(null, function () { 155 throw new \Exception('UnhandledRejectionException'); 156 })); 157 $adapter->reject(1); 158 } 159 160 /** @test */ 161 public function doneShouldThrowUnhandledRejectionExceptionWhenRejectedWithNonException() 162 { 163 $adapter = $this->getPromiseTestAdapter(); 164 165 $this->setExpectedException('React\\Promise\\UnhandledRejectionException'); 166 167 $this->assertNull($adapter->promise()->done()); 168 $adapter->reject(1); 169 } 170 171 /** @test */ 172 public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRejects() 173 { 174 $adapter = $this->getPromiseTestAdapter(); 175 176 $this->setExpectedException('React\\Promise\\UnhandledRejectionException'); 177 178 $this->assertNull($adapter->promise()->done(null, function () { 179 return \React\Promise\reject(); 180 })); 181 $adapter->reject(1); 182 } 183 184 /** @test */ 185 public function doneShouldThrowRejectionExceptionWhenRejectionHandlerRejectsWithException() 186 { 187 $adapter = $this->getPromiseTestAdapter(); 188 189 $this->setExpectedException('\Exception', 'UnhandledRejectionException'); 190 191 $this->assertNull($adapter->promise()->done(null, function () { 192 return \React\Promise\reject(new \Exception('UnhandledRejectionException')); 193 })); 194 $adapter->reject(1); 195 } 196 197 /** @test */ 198 public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRetunsPendingPromiseWhichRejectsLater() 199 { 200 $adapter = $this->getPromiseTestAdapter(); 201 202 $this->setExpectedException('React\\Promise\\UnhandledRejectionException'); 203 204 $d = new Deferred(); 205 $promise = $d->promise(); 206 207 $this->assertNull($adapter->promise()->done(null, function () use ($promise) { 208 return $promise; 209 })); 210 $adapter->reject(1); 211 $d->reject(1); 212 } 213 214 /** @test */ 215 public function doneShouldThrowExceptionProvidedAsRejectionValue() 216 { 217 $adapter = $this->getPromiseTestAdapter(); 218 219 $this->setExpectedException('\Exception', 'UnhandledRejectionException'); 220 221 $this->assertNull($adapter->promise()->done()); 222 $adapter->reject(new \Exception('UnhandledRejectionException')); 223 } 224 225 /** @test */ 226 public function doneShouldThrowWithDeepNestingPromiseChains() 227 { 228 $this->setExpectedException('\Exception', 'UnhandledRejectionException'); 229 230 $exception = new \Exception('UnhandledRejectionException'); 231 232 $d = new Deferred(); 233 234 $result = \React\Promise\resolve(\React\Promise\resolve($d->promise()->then(function () use ($exception) { 235 $d = new Deferred(); 236 $d->resolve(); 237 238 return \React\Promise\resolve($d->promise()->then(function () {}))->then( 239 function () use ($exception) { 240 throw $exception; 241 } 242 ); 243 }))); 244 245 $result->done(); 246 247 $d->resolve(); 248 } 249 250 /** @test */ 251 public function doneShouldRecoverWhenRejectionHandlerCatchesException() 252 { 253 $adapter = $this->getPromiseTestAdapter(); 254 255 $this->assertNull($adapter->promise()->done(null, function (\Exception $e) { 256 257 })); 258 $adapter->reject(new \Exception('UnhandledRejectionException')); 259 } 260 261 /** @test */ 262 public function alwaysShouldNotSuppressRejection() 263 { 264 $adapter = $this->getPromiseTestAdapter(); 265 266 $exception = new \Exception(); 267 268 $mock = $this->createCallableMock(); 269 $mock 270 ->expects($this->once()) 271 ->method('__invoke') 272 ->with($this->identicalTo($exception)); 273 274 $adapter->promise() 275 ->always(function () {}) 276 ->then(null, $mock); 277 278 $adapter->reject($exception); 279 } 280 281 /** @test */ 282 public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromise() 283 { 284 $adapter = $this->getPromiseTestAdapter(); 285 286 $exception = new \Exception(); 287 288 $mock = $this->createCallableMock(); 289 $mock 290 ->expects($this->once()) 291 ->method('__invoke') 292 ->with($this->identicalTo($exception)); 293 294 $adapter->promise() 295 ->always(function () { 296 return 1; 297 }) 298 ->then(null, $mock); 299 300 $adapter->reject($exception); 301 } 302 303 /** @test */ 304 public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromise() 305 { 306 $adapter = $this->getPromiseTestAdapter(); 307 308 $exception = new \Exception(); 309 310 $mock = $this->createCallableMock(); 311 $mock 312 ->expects($this->once()) 313 ->method('__invoke') 314 ->with($this->identicalTo($exception)); 315 316 $adapter->promise() 317 ->always(function () { 318 return \React\Promise\resolve(1); 319 }) 320 ->then(null, $mock); 321 322 $adapter->reject($exception); 323 } 324 325 /** @test */ 326 public function alwaysShouldRejectWhenHandlerThrowsForRejection() 327 { 328 $adapter = $this->getPromiseTestAdapter(); 329 330 $exception = new \Exception(); 331 332 $mock = $this->createCallableMock(); 333 $mock 334 ->expects($this->once()) 335 ->method('__invoke') 336 ->with($this->identicalTo($exception)); 337 338 $adapter->promise() 339 ->always(function () use ($exception) { 340 throw $exception; 341 }) 342 ->then(null, $mock); 343 344 $adapter->reject($exception); 345 } 346 347 /** @test */ 348 public function alwaysShouldRejectWhenHandlerRejectsForRejection() 349 { 350 $adapter = $this->getPromiseTestAdapter(); 351 352 $exception = new \Exception(); 353 354 $mock = $this->createCallableMock(); 355 $mock 356 ->expects($this->once()) 357 ->method('__invoke') 358 ->with($this->identicalTo($exception)); 359 360 $adapter->promise() 361 ->always(function () use ($exception) { 362 return \React\Promise\reject($exception); 363 }) 364 ->then(null, $mock); 365 366 $adapter->reject($exception); 367 } 368} 369