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