1# Functions that contain the `await` keyword will compile into async functions, 2# supported by Node 7.6+, Chrome 55+, Firefox 52+, Safari 10.1+ and Edge. 3# But runtimes that don’t support the `await` keyword will throw an error just 4# from parsing this file, even without executing it, even if we put 5# `return unless try new Function 'async () => {}'` at the top of this file. 6# Therefore we need to prevent runtimes which will choke on such code from 7# parsing it, which is handled in `Cakefile`. 8 9 10# This is always fulfilled. 11winning = (val) -> Promise.resolve val 12 13# This is always rejected. 14failing = (val) -> Promise.reject new Error val 15 16 17test "async as argument", -> 18 ok -> 19 await winning() 20 21test "explicit async", -> 22 a = do -> 23 await return 5 24 eq a.constructor, Promise 25 a.then (val) -> 26 eq val, 5 27 28test "implicit async", -> 29 a = do -> 30 x = await winning(5) 31 y = await winning(4) 32 z = await winning(3) 33 [x, y, z] 34 35 eq a.constructor, Promise 36 37test "async return value (implicit)", -> 38 out = null 39 a = -> 40 x = await winning(5) 41 y = await winning(4) 42 z = await winning(3) 43 [x, y, z] 44 45 b = do -> 46 out = await a() 47 48 b.then -> 49 arrayEq out, [5, 4, 3] 50 51test "async return value (explicit)", -> 52 out = null 53 a = -> 54 await return [5, 2, 3] 55 56 b = do -> 57 out = await a() 58 59 b.then -> 60 arrayEq out, [5, 2, 3] 61 62 63test "async parameters", -> 64 [out1, out2] = [null, null] 65 a = (a, [b, c])-> 66 arr = [a] 67 arr.push b 68 arr.push c 69 await return arr 70 71 b = (a, b, c = 5)-> 72 arr = [a] 73 arr.push b 74 arr.push c 75 await return arr 76 77 c = do -> 78 out1 = await a(5, [4, 3]) 79 out2 = await b(4, 4) 80 81 c.then -> 82 arrayEq out1, [5, 4, 3] 83 arrayEq out2, [4, 4, 5] 84 85test "async `this` scoping", -> 86 bnd = null 87 ubnd = null 88 nst = null 89 obj = 90 bound: -> 91 return do => 92 await return this 93 unbound: -> 94 return do -> 95 await return this 96 nested: -> 97 return do => 98 await do => 99 await do => 100 await return this 101 102 promise = do -> 103 bnd = await obj.bound() 104 ubnd = await obj.unbound() 105 nst = await obj.nested() 106 107 promise.then -> 108 eq bnd, obj 109 ok ubnd isnt obj 110 eq nst, obj 111 112test "await precedence", -> 113 out = null 114 115 fn = (win, fail) -> 116 win(3) 117 118 promise = do -> 119 # assert precedence between unary (new) and power (**) operators 120 out = 1 + await new Promise(fn) ** 2 121 122 promise.then -> 123 eq out, 10 124 125test "`await` inside IIFEs", -> 126 [x, y, z] = new Array(3) 127 128 a = do -> 129 x = switch (4) # switch 4 130 when 2 131 await winning(1) 132 when 4 133 await winning(5) 134 when 7 135 await winning(2) 136 137 y = try 138 text = "this should be caught" 139 throw new Error(text) 140 await winning(1) 141 catch e 142 await winning(4) 143 144 z = for i in [0..5] 145 a = i * i 146 await winning(a) 147 148 a.then -> 149 eq x, 5 150 eq y, 4 151 152 arrayEq z, [0, 1, 4, 9, 16, 25] 153 154test "error handling", -> 155 res = null 156 val = 0 157 a = -> 158 try 159 await failing("fail") 160 catch e 161 val = 7 # to assure the catch block runs 162 return e 163 164 b = do -> 165 res = await a() 166 167 b.then -> 168 eq val, 7 169 170 ok res.message? 171 eq res.message, "fail" 172 173test "await expression evaluates to argument if not A+", -> 174 eq(await 4, 4) 175 176 177test "implicit call with `await`", -> 178 addOne = (arg) -> arg + 1 179 180 a = addOne await 3 181 eq a, 4 182 183test "async methods in classes", -> 184 class Base 185 @static: -> 186 await 1 187 method: -> 188 await 2 189 190 eq await Base.static(), 1 191 eq await new Base().method(), 2 192 193 class Child extends Base 194 @static: -> super() 195 method: -> super() 196 197 eq await Child.static(), 1 198 eq await new Child().method(), 2 199 200test "#3199: await multiline implicit object", -> 201 do -> 202 y = 203 if no then await 204 type: 'a' 205 msg: 'b' 206 eq undefined, y 207 208test "top-level await", -> 209 eqJS 'await null', 'await null;' 210 211test "top-level wrapper has correct async attribute", -> 212 starts = (code, prefix) -> 213 compiled = CoffeeScript.compile code 214 unless compiled.startsWith prefix 215 fail """Expected generated JavaScript to start with: 216 #{reset}#{prefix}#{red} 217 but instead it was: 218 #{reset}#{compiled}#{red}""" 219 starts 'await null', '(async function' 220 starts 'do -> await null', '(function' 221