return function()local v=require(script.Parent)v.TEST=true local D=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")v._timeEvent=D.Event local e do local p=0 v._getTime=function()return p end function e(v)v=v or.016666666666667 p=p+v D:Fire(v)end end local function p(...)local v=select("\035",...)return v,{...}end describe("\080\114\111\109\105\115\101\046\083\116\097\116\117\115",function()it("\115\104\111\117\108\100 \101\114\114\111\114 \105\102 \105\110\100\101\120\105\110\103 \110\105\108 \118\097\108\117\101",function()(expect(function()local D=v.Status.wrong end)).to.throw()end)end)describe("\085\110\104\097\110\100\108\101\100 \114\101\106\101\099\116\105\111\110 \115\105\103\110\097\108",function()it("\115\104\111\117\108\100 \099\097\108\108 \117\110\104\097\110\100\108\101\100 \114\101\106\101\099\116\105\111\110 \099\097\108\108\098\097\099\107\115",function()local D=v.new(function(v,D)D(1,2)end)local p=0 local function O(v,e,O)p+=1;(expect(v)).to.equal(D);(expect(e)).to.equal(1);(expect(O)).to.equal(2)end local G=v.onUnhandledRejection(O)e();(expect(p)).to.equal(1)G()v.new(function(v,D)D(3,4)end)e();(expect(p)).to.equal(1)end)end)describe("\080\114\111\109\105\115\101\046\110\101\119",function()it("\115\104\111\117\108\100 \105\110\115\116\097\110\116\105\097\116\101 \119\105\116\104 \097 \099\097\108\108\098\097\099\107",function()local D=v.new(function() end);(expect(D)).to.be.ok()end)it("\115\104\111\117\108\100 \105\110\118\111\107\101 \116\104\101 \103\105\118\101\110 \099\097\108\108\098\097\099\107 \119\105\116\104 \114\101\115\111\108\118\101 \097\110\100 \114\101\106\101\099\116",function()local D=0 local e local p local O=v.new(function(v,O)D=D+1 e=v p=O end);(expect(O)).to.be.ok();(expect(D)).to.equal(1);(expect(e)).to.be.a("\102\117\110\099\116\105\111\110");(expect(p)).to.be.a("\102\117\110\099\116\105\111\110");(expect(O:getStatus())).to.equal(v.Status.Started)end)it("\115\104\111\117\108\100 \114\101\115\111\108\118\101 \112\114\111\109\105\115\101\115 \111\110 \114\101\115\111\108\118\101\040\041",function()local D=0 local e=v.new(function(v)D=D+1 v()end);(expect(e)).to.be.ok();(expect(D)).to.equal(1);(expect(e:getStatus())).to.equal(v.Status.Resolved)end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \112\114\111\109\105\115\101\115 \111\110 \114\101\106\101\099\116\040\041",function()local D=0 local e=v.new(function(v,e)D=D+1 e()end);(expect(e)).to.be.ok();(expect(D)).to.equal(1);(expect(e:getStatus())).to.equal(v.Status.Rejected)end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \111\110 \101\114\114\111\114 \105\110 \099\097\108\108\098\097\099\107",function()local D=0 local e=v.new(function()D=D+1 error("\104\097\104\097\104")end);(expect(e)).to.be.ok();(expect(D)).to.equal(1);(expect(e:getStatus())).to.equal(v.Status.Rejected);(expect((tostring(e._values[1])):find("\104\097\104\097\104"))).to.be.ok();(expect((tostring(e._values[1])):find("\105\110\105\116\046\115\112\101\099"))).to.be.ok();(expect((tostring(e._values[1])):find("\114\117\110\069\120\101\099\117\116\111\114"))).to.be.ok()end)it("\115\104\111\117\108\100 \119\111\114\107 \119\105\116\104 \067 \102\117\110\099\116\105\111\110\115",function()(expect(function()(v.new(tick)):andThen(tick)end)).to.never.throw()end)it("\115\104\111\117\108\100 \104\097\118\101 \097 \110\105\099\101 \116\111\115\116\114\105\110\103",function()(expect((tostring(v.resolve())):gmatch("\080\114\111\109\105\115\101\040\082\101\115\111\108\118\101\100\041"))).to.be.ok()end)it("\115\104\111\117\108\100 \097\108\108\111\119 \121\105\101\108\100\105\110\103",function()local D=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")local e=v.new(function(v)D.Event:Wait()v(5)end);(expect(e:getStatus())).to.equal(v.Status.Started)D:Fire();(expect(e:getStatus())).to.equal(v.Status.Resolved);(expect(e._values[1])).to.equal(5)end)it("\115\104\111\117\108\100 \112\114\101\115\101\114\118\101 \115\116\097\099\107 \116\114\097\099\101\115 \111\102 \114\101\115\111\108\118\101-\099\104\097\105\110\101\100 \112\114\111\109\105\115\101\115",function()local function D(v)error(v)end local e=v.new(function(e)e(v.new(function()D("\115\097\109\112\108\101 \116\101\120\116")end))end);(expect(e:getStatus())).to.equal(v.Status.Rejected)local p=tostring(e._values[1]);(expect(p:find("\115\097\109\112\108\101 \116\101\120\116"))).to.be.ok();(expect(p:find("\110\101\115\116\101\100\067\097\108\108"))).to.be.ok();(expect(p:find("\114\117\110\069\120\101\099\117\116\111\114"))).to.be.ok();(expect(p:find("\114\117\110\080\108\097\110\078\111\100\101"))).to.be.ok();(expect(p:find("\046\046\046\082\101\106\101\099\116\101\100 \098\101\099\097\117\115\101 \105\116 \119\097\115 \099\104\097\105\110\101\100 \116\111 \116\104\101 \102\111\108\108\111\119\105\110\103 \080\114\111\109\105\115\101\044 \119\104\105\099\104 \101\110\099\111\117\110\116\101\114\101\100 \097\110 \101\114\114\111\114\058"))).to.be.ok()end)it("\115\104\111\117\108\100 \114\101\112\111\114\116 \101\114\114\111\114\115 \102\114\111\109 \080\114\111\109\105\115\101\115 \119\105\116\104 \095\101\114\114\111\114 \040\060 \118\050\041",function()local D=v.reject()D._error="\083\097\109\112\108\101 \101\114\114\111\114"local e=(v.resolve()):andThenReturn(D);(expect(e:getStatus())).to.equal(v.Status.Rejected)local p=tostring(e._values[1]);(expect(p:find("\083\097\109\112\108\101 \101\114\114\111\114"))).to.be.ok();(expect(p:find("\046\046\046\082\101\106\101\099\116\101\100 \098\101\099\097\117\115\101 \105\116 \119\097\115 \099\104\097\105\110\101\100 \116\111 \116\104\101 \102\111\108\108\111\119\105\110\103 \080\114\111\109\105\115\101\044 \119\104\105\099\104 \101\110\099\111\117\110\116\101\114\101\100 \097\110 \101\114\114\111\114\058"))).to.be.ok();(expect(p:find("\037\091\078\111 \115\116\097\099\107 \116\114\097\099\101 \097\118\097\105\108\097\098\108\101"))).to.be.ok()end)it("\115\104\111\117\108\100 \097\108\108\111\119 \099\097\108\108\097\098\108\101 \116\097\098\108\101\115",function()local D=v.new(setmetatable({},{__call=function(v,D)D(1)end}))local e=false D:andThen(setmetatable({},{__call=function(v,D)(expect(D)).to.equal(1)e=true end}));(expect(e)).to.equal(true)end)itSKIP("\115\104\111\117\108\100 \099\108\111\115\101 \116\104\101 \116\104\114\101\097\100 \097\102\116\101\114 \114\101\115\111\108\118\101",function()local D=0 v.new(function(e)D+=1 e();(v.delay(1)):await()D+=1 end)task.wait(1);(expect(D)).to.equal(1)end)end)describe("\080\114\111\109\105\115\101\046\100\101\102\101\114",function()it("\115\104\111\117\108\100 \101\120\101\099\117\116\101 \097\102\116\101\114 \116\104\101 \116\105\109\101 \101\118\101\110\116",function()local D=0 local p=v.defer(function(v,e,p,O)(expect(type(v))).to.equal("\102\117\110\099\116\105\111\110");(expect(type(e))).to.equal("\102\117\110\099\116\105\111\110");(expect(type(p))).to.equal("\102\117\110\099\116\105\111\110");(expect(type(O))).to.equal("\110\105\108")D=D+1 v("\102\111\111")end);(expect(D)).to.equal(0);(expect(p:getStatus())).to.equal(v.Status.Started)e();(expect(D)).to.equal(1);(expect(p:getStatus())).to.equal(v.Status.Resolved)e();(expect(D)).to.equal(1)end)end)describe("\080\114\111\109\105\115\101\046\100\101\108\097\121",function()it("\115\104\111\117\108\100 \115\099\104\101\100\117\108\101 \112\114\111\109\105\115\101 \114\101\115\111\108\117\116\105\111\110",function()local D=v.delay(1);(expect(D:getStatus())).to.equal(v.Status.Started)e();(expect(D:getStatus())).to.equal(v.Status.Started)e(1);(expect(D:getStatus())).to.equal(v.Status.Resolved)end)it("\115\104\111\117\108\100 \097\108\108\111\119 \102\111\114 \100\101\108\097\121\115 \116\111 \098\101 \099\097\110\099\101\108\108\101\100",function()local D=v.delay(2);(v.delay(1)):andThen(function()D:cancel()end);(expect(D:getStatus())).to.equal(v.Status.Started)e();(expect(D:getStatus())).to.equal(v.Status.Started)e(1);(expect(D:getStatus())).to.equal(v.Status.Cancelled)e(1)end)end)describe("\080\114\111\109\105\115\101\046\114\101\115\111\108\118\101",function()it("\115\104\111\117\108\100 \105\109\109\101\100\105\097\116\101\108\121 \114\101\115\111\108\118\101 \119\105\116\104 \097 \118\097\108\117\101",function()local D=v.resolve(5,6);(expect(D)).to.be.ok();(expect(D:getStatus())).to.equal(v.Status.Resolved);(expect(D._values[1])).to.equal(5);(expect(D._values[2])).to.equal(6)end)it("\115\104\111\117\108\100 \099\104\097\105\110 \111\110\116\111 \112\097\115\115\101\100 \112\114\111\109\105\115\101\115",function()local D=v.resolve(v.new(function(v,D)D(7)end));(expect(D)).to.be.ok();(expect(D:getStatus())).to.equal(v.Status.Rejected);(expect(D._values[1])).to.equal(7)end)end)describe("\080\114\111\109\105\115\101\046\114\101\106\101\099\116",function()it("\115\104\111\117\108\100 \105\109\109\101\100\105\097\116\101\108\121 \114\101\106\101\099\116 \119\105\116\104 \097 \118\097\108\117\101",function()local D=v.reject(6,7);(expect(D)).to.be.ok();(expect(D:getStatus())).to.equal(v.Status.Rejected);(expect(D._values[1])).to.equal(6);(expect(D._values[2])).to.equal(7)end)it("\115\104\111\117\108\100 \112\097\115\115 \097 \112\114\111\109\105\115\101 \097\115-\105\115 \097\115 \097\110 \101\114\114\111\114",function()local D=v.new(function(v)v(6)end)local e=v.reject(D);(expect(e)).to.be.ok();(expect(e:getStatus())).to.equal(v.Status.Rejected);(expect(e._values[1])).to.equal(D)end)end)describe("\080\114\111\109\105\115\101\058\097\110\100\084\104\101\110",function()it("\115\104\111\117\108\100 \097\108\108\111\119 \121\105\101\108\100\105\110\103",function()local D=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")local e=(v.resolve()):andThen(function()D.Event:Wait()return 5 end);(expect(e:getStatus())).to.equal(v.Status.Started)D:Fire();(expect(e:getStatus())).to.equal(v.Status.Resolved);(expect(e._values[1])).to.equal(5)end)it("\115\104\111\117\108\100 \114\117\110 \097\110\100\084\104\101\110\115 \111\110 \097 \110\101\119 \116\104\114\101\097\100",function()local D=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")local e local p=v.new(function(v)e=v end)local O=p:andThen(function()D.Event:Wait()return 5 end)local G=p:andThen(function()return"\102\111\111"end);(expect(p:getStatus())).to.equal(v.Status.Started)e();(expect(G:getStatus())).to.equal(v.Status.Resolved);(expect(G._values[1])).to.equal("\102\111\111");(expect(O:getStatus())).to.equal(v.Status.Started)end)it("\115\104\111\117\108\100 \099\104\097\105\110 \111\110\116\111 \114\101\115\111\108\118\101\100 \112\114\111\109\105\115\101\115",function()local D local e local O=0 local G=0 local C=v.resolve(5)local R=C:andThen(function(...)e,D=p(...)O=O+1 end,function()G=G+1 end);(expect(G)).to.equal(0);(expect(O)).to.equal(1);(expect(e)).to.equal(1);(expect(D[1])).to.equal(5);(expect(C)).to.be.ok();(expect(C:getStatus())).to.equal(v.Status.Resolved);(expect(C._values[1])).to.equal(5);(expect(R)).to.be.ok();(expect(R)).never.to.equal(C);(expect(R:getStatus())).to.equal(v.Status.Resolved);(expect(#R._values)).to.equal(0)end)it("\115\104\111\117\108\100 \099\104\097\105\110 \111\110\116\111 \114\101\106\101\099\116\101\100 \112\114\111\109\105\115\101\115",function()local D local e local O=0 local G=0 local C=v.reject(5)local R=C:andThen(function(...)G=G+1 end,function(...)e,D=p(...)O=O+1 end);(expect(G)).to.equal(0);(expect(O)).to.equal(1);(expect(e)).to.equal(1);(expect(D[1])).to.equal(5);(expect(C)).to.be.ok();(expect(C:getStatus())).to.equal(v.Status.Rejected);(expect(C._values[1])).to.equal(5);(expect(R)).to.be.ok();(expect(R)).never.to.equal(C);(expect(R:getStatus())).to.equal(v.Status.Resolved);(expect(#R._values)).to.equal(0)end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \111\110 \101\114\114\111\114 \105\110 \099\097\108\108\098\097\099\107",function()local D=0 local e=(v.resolve(1)):andThen(function()D=D+1 error("\104\097\104\097\104")end);(expect(e)).to.be.ok();(expect(D)).to.equal(1);(expect(e:getStatus())).to.equal(v.Status.Rejected);(expect((tostring(e._values[1])):find("\104\097\104\097\104"))).to.be.ok();(expect((tostring(e._values[1])):find("\105\110\105\116\046\115\112\101\099"))).to.be.ok();(expect((tostring(e._values[1])):find("\114\117\110\069\120\101\099\117\116\111\114"))).to.be.ok()end)it("\115\104\111\117\108\100 \099\104\097\105\110 \111\110\116\111 \097\115\121\110\099\104\114\111\110\111\117\115\108\121 \114\101\115\111\108\118\101\100 \112\114\111\109\105\115\101\115",function()local D local e local p=0 local O=0 local G local C=v.new(function(v)G=v end)local R=C:andThen(function(...)D={...}e=select("\035",...)p=p+1 end,function()O=O+1 end);(expect(p)).to.equal(0);(expect(O)).to.equal(0)G(6);(expect(O)).to.equal(0);(expect(p)).to.equal(1);(expect(e)).to.equal(1);(expect(D[1])).to.equal(6);(expect(C)).to.be.ok();(expect(C:getStatus())).to.equal(v.Status.Resolved);(expect(C._values[1])).to.equal(6);(expect(R)).to.be.ok();(expect(R)).never.to.equal(C);(expect(R:getStatus())).to.equal(v.Status.Resolved);(expect(#R._values)).to.equal(0)end)it("\115\104\111\117\108\100 \099\104\097\105\110 \111\110\116\111 \097\115\121\110\099\104\114\111\110\111\117\115\108\121 \114\101\106\101\099\116\101\100 \112\114\111\109\105\115\101\115",function()local D local e local p=0 local O=0 local G local C=v.new(function(v,D)G=D end)local R=C:andThen(function()O=O+1 end,function(...)D={...}e=select("\035",...)p=p+1 end);(expect(p)).to.equal(0);(expect(O)).to.equal(0)G(6);(expect(O)).to.equal(0);(expect(p)).to.equal(1);(expect(e)).to.equal(1);(expect(D[1])).to.equal(6);(expect(C)).to.be.ok();(expect(C:getStatus())).to.equal(v.Status.Rejected);(expect(C._values[1])).to.equal(6);(expect(R)).to.be.ok();(expect(R)).never.to.equal(C);(expect(R:getStatus())).to.equal(v.Status.Resolved);(expect(#R._values)).to.equal(0)end)it("\115\104\111\117\108\100 \112\114\111\112\097\103\097\116\101 \101\114\114\111\114\115 \116\104\114\111\117\103\104 \109\117\108\116\105\112\108\101 \108\101\118\101\108\115",function()local D,e,p;((v.new(function(v,D)D(1,2,3)end)):andThen(function() end)):catch(function(v,O,G)D,e,p=v,O,G end);(expect(D)).to.equal(1);(expect(e)).to.equal(2);(expect(p)).to.equal(3)end)it("\115\104\111\117\108\100 \110\111\116 \099\097\108\108 \113\117\101\117\101\100 \099\097\108\108\098\097\099\107\115 \102\114\111\109 \097 \099\097\110\099\101\108\108\101\100 \115\117\098-\112\114\111\109\105\115\101",function()local D local e=0 local p=v.new(function(v)D=v end)p:andThen(function()e+=1 end);(p:andThen(function()e+=1 end)):cancel()D("\102\111\111");(expect(e)).to.equal(1)end)end)describe("\080\114\111\109\105\115\101\058\099\097\110\099\101\108",function()it("\115\104\111\117\108\100 \109\097\114\107 \112\114\111\109\105\115\101\115 \097\115 \099\097\110\099\101\108\108\101\100 \097\110\100 \110\111\116 \114\101\115\111\108\118\101 \111\114 \114\101\106\101\099\116 \116\104\101\109",function()local D=0 local e=0 local p=((v.new(function() end)):andThen(function()D=D+1 end)):finally(function()e=e+1 end)p:cancel()p:cancel();(expect(D)).to.equal(0);(expect(e)).to.equal(1);(expect(p:getStatus())).to.equal(v.Status.Cancelled)end)it("\115\104\111\117\108\100 \099\097\108\108 \116\104\101 \099\097\110\099\101\108\108\097\116\105\111\110 \104\111\111\107 \111\110\099\101",function()local D=0 local e=v.new(function(v,e,p)p(function()D=D+1 end)end)e:cancel()e:cancel();(expect(D)).to.equal(1)end)it("\115\104\111\117\108\100 \112\114\111\112\097\103\097\116\101 \099\097\110\099\101\108\108\097\116\105\111\110\115",function()local D=v.new(function() end)local e=D:andThen()local p=D:andThen();(expect(D:getStatus())).to.equal(v.Status.Started);(expect(e:getStatus())).to.equal(v.Status.Started);(expect(p:getStatus())).to.equal(v.Status.Started)e:cancel();(expect(D:getStatus())).to.equal(v.Status.Started);(expect(e:getStatus())).to.equal(v.Status.Cancelled);(expect(p:getStatus())).to.equal(v.Status.Started)p:cancel();(expect(D:getStatus())).to.equal(v.Status.Cancelled);(expect(e:getStatus())).to.equal(v.Status.Cancelled);(expect(p:getStatus())).to.equal(v.Status.Cancelled)end)it("\115\104\111\117\108\100 \097\102\102\101\099\116 \100\111\119\110\115\116\114\101\097\109 \112\114\111\109\105\115\101\115",function()local D=v.new(function() end)local e=D:andThen()D:cancel();(expect(e:getStatus())).to.equal(v.Status.Cancelled)end)it("\115\104\111\117\108\100 \116\114\097\099\107 \099\111\110\115\117\109\101\114\115",function()local D=v.new(function() end)local e=v.resolve()local p=e:andThen(function()return D end)local O=v.new(function(v)v(p)end)local G=O:andThen(function() end);(expect(p._parent)).to.never.equal(e);(expect(O._parent)).to.never.equal(p);(expect(O._consumers[G])).to.be.ok();(expect(G._parent)).to.equal(O)end)it("\115\104\111\117\108\100 \099\097\110\099\101\108 \114\101\115\111\108\118\101\100 \112\101\110\100\105\110\103 \112\114\111\109\105\115\101\115",function()local D=v.new(function() end)local e=(v.new(function(v)v(D)end)):finally(function() end)e:cancel();(expect(D._status)).to.equal(v.Status.Cancelled);(expect(e._status)).to.equal(v.Status.Cancelled)end)it("\115\104\111\117\108\100 \099\108\111\115\101 \116\104\101 \112\114\111\109\105\115\101 \116\104\114\101\097\100",function()local D=0 local p=v.new(function()D+=1;(v.delay(1)):await()D+=1 end)p:cancel()e(2);(expect(D)).to.equal(1)end)end)describe("\080\114\111\109\105\115\101\058\102\105\110\097\108\108\121",function()it("\115\104\111\117\108\100 \098\101 \099\097\108\108\101\100 \117\112\111\110 \114\101\115\111\108\118\101\044 \114\101\106\101\099\116\044 \111\114 \099\097\110\099\101\108",function()local D=0 local function e()D=D+1 end;(v.new(function(v,D)v()end)):finally(e);(((v.resolve()):andThen(function() end)):finally(e)):finally(e);(v.reject()):finally(e)local p=(v.new(function() end)):finally(e)p:cancel();(expect(D)).to.equal(5)end)it("\115\104\111\117\108\100 \110\111\116 \102\111\114\119\097\114\100 \114\101\116\117\114\110 \118\097\108\117\101\115",function()local D;((v.resolve(2)):finally(function()return 1 end)):andThen(function(v)D=v end);(expect(D)).to.equal(2)end)it("\115\104\111\117\108\100 \110\111\116 \099\111\110\115\117\109\101 \114\101\106\101\099\116\105\111\110\115",function()local D=false local e=false;(((v.reject(5)):finally(function()return 42 end)):andThen(function()e=true end)):catch(function(v)D=true;(expect(v)).to.equal(5)end);(expect(D)).to.equal(true);(expect(e)).to.equal(false)end)it("\115\104\111\117\108\100 \119\097\105\116 \102\111\114 \114\101\116\117\114\110\101\100 \112\114\111\109\105\115\101\115",function()local D local e=(v.reject("\102\111\111")):finally(function()return v.new(function(v)D=v end)end);(expect(e:getStatus())).to.equal(v.Status.Started)D();(expect(e:getStatus())).to.equal(v.Status.Rejected)local p,O=e:_unwrap();(expect(O)).to.equal("\102\111\111")end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \119\105\116\104 \097 \114\101\116\117\114\110\101\100 \114\101\106\101\099\116\101\100 \112\114\111\109\105\115\101\'\115 \118\097\108\117\101",function()local D local e=(v.reject("\102\111\111")):finally(function()return v.new(function(v,e)D=e end)end);(expect(e:getStatus())).to.equal(v.Status.Started)D("\098\097\114");(expect(e:getStatus())).to.equal(v.Status.Rejected)local p,O=e:_unwrap();(expect(O)).to.equal("\098\097\114")end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \119\104\101\110 \104\097\110\100\108\101\114 \101\114\114\111\114\115",function()local D={}local e=(v.reject("\098\097\114")):finally(function()error(D)end)local p,O=e:_unwrap();(expect(p)).to.equal(false);(expect(O)).to.equal(D)end)it("\115\104\111\117\108\100 \110\111\116 \112\114\101\118\101\110\116 \099\097\110\099\101\108\108\097\116\105\111\110",function()local D=v.new(function() end)local e=false D:finally(function()e=true end)local p=D:andThen(function() end)p:cancel();(expect(D:getStatus())).to.equal(v.Status.Cancelled);(expect(e)).to.equal(true)end)it("\115\104\111\117\108\100 \112\114\111\112\097\103\097\116\101 \099\097\110\099\101\108\108\097\116\105\111\110 \100\111\119\110\119\097\114\100\115",function()local D=false local e=false local p=v.new(function() end)local O=p:finally(function()D=true end)p:cancel();(expect(p:getStatus())).to.equal(v.Status.Cancelled);(expect(O:getStatus())).to.equal(v.Status.Cancelled);(expect(D)).to.equal(true);(expect(e)).to.equal(false)end)it("\115\104\111\117\108\100 \112\114\111\112\097\103\097\116\101 \099\097\110\099\101\108\108\097\116\105\111\110 \117\112\119\097\114\100\115",function()local D=false local e=false local p=v.new(function() end)local O=p:finally(function()D=true end)O:cancel();(expect(p:getStatus())).to.equal(v.Status.Cancelled);(expect(O:getStatus())).to.equal(v.Status.Cancelled);(expect(D)).to.equal(true);(expect(e)).to.equal(false)end)it("\115\104\111\117\108\100 \099\097\110\099\101\108 \114\101\116\117\114\110\101\100 \112\114\111\109\105\115\101 \105\102 \099\097\110\099\101\108\108\101\100",function()local D=v.new(function() end)local e=(v.resolve()):finally(function()return D end)e:cancel();(expect(D:getStatus())).to.equal(v.Status.Cancelled)end)end)describe("\080\114\111\109\105\115\101\046\097\108\108",function()it("\115\104\111\117\108\100 \101\114\114\111\114 \105\102 \103\105\118\101\110 \115\111\109\101\116\104\105\110\103 \111\116\104\101\114 \116\104\097\110 \097 \116\097\098\108\101",function()(expect(function()v.all(1)end)).to.throw()end)it("\115\104\111\117\108\100 \114\101\115\111\108\118\101 \105\110\115\116\097\110\116\108\121 \119\105\116\104 \097\110 \101\109\112\116\121 \116\097\098\108\101 \105\102 \103\105\118\101\110 \110\111 \112\114\111\109\105\115\101\115",function()local D=v.all({})local e,p=D:_unwrap();(expect(e)).to.equal(true);(expect(D:getStatus())).to.equal(v.Status.Resolved);(expect(p)).to.be.a("\116\097\098\108\101");(expect(next(p))).to.equal(nil)end)it("\115\104\111\117\108\100 \101\114\114\111\114 \105\102 \103\105\118\101\110 \110\111\110-\112\114\111\109\105\115\101 \118\097\108\117\101\115",function()(expect(function()v.all({{};{};{}})end)).to.throw()end)it("\115\104\111\117\108\100 \119\097\105\116 \102\111\114 \097\108\108 \112\114\111\109\105\115\101\115 \116\111 \098\101 \114\101\115\111\108\118\101\100 \097\110\100 \114\101\116\117\114\110 \116\104\101\105\114 \118\097\108\117\101\115",function()local D={}local e,O=p(1,"\065 \115\116\114\105\110\103",nil,false)local G={}for e=1,e,1 do G[e]=v.new(function(v)D[e]={v,O[e]}end)end local C=v.all(G)for D,e in ipairs(D)do(expect(C:getStatus())).to.equal(v.Status.Started)e[1](e[2])end local R,m=p(C:_unwrap())local r,g=unpack(m,1,R);(expect(R)).to.equal(2);(expect(r)).to.equal(true);(expect(g)).to.be.a("\116\097\098\108\101");(expect(#g)).to.equal(#G)for v=1,e,1 do(expect(g[v])).to.equal(O[v])end end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \105\102 \097\110\121 \105\110\100\105\118\105\100\117\097\108 \112\114\111\109\105\115\101 \114\101\106\101\099\116\101\100",function()local D local e local O=v.new(function(v,e)D=e end)local G=v.new(function(v)e=v end)local C=v.all({O;G});(expect(C:getStatus())).to.equal(v.Status.Started)D("\098\097\122","\113\117\120")e("\102\111\111","\098\097\114")local R,m=p(C:_unwrap())local r,g,a=unpack(m,1,R);(expect(R)).to.equal(3);(expect(r)).to.equal(false);(expect(g)).to.equal("\098\097\122");(expect(a)).to.equal("\113\117\120");(expect(G:getStatus())).to.equal(v.Status.Cancelled)end)it("\115\104\111\117\108\100 \110\111\116 \114\101\115\111\108\118\101 \105\102 \114\101\115\111\108\118\101\100 \097\102\116\101\114 \114\101\106\101\099\116\105\110\103",function()local D local e local O=v.new(function(v,e)D=e end)local G=v.new(function(v)e=v end)local C=v.all({O;G});(expect(C:getStatus())).to.equal(v.Status.Started)D("\098\097\122","\113\117\120")e("\102\111\111","\098\097\114")local R,m=p(C:_unwrap())local r,g,a=unpack(m,1,R);(expect(R)).to.equal(3);(expect(r)).to.equal(false);(expect(g)).to.equal("\098\097\122");(expect(a)).to.equal("\113\117\120")end)it("\115\104\111\117\108\100 \111\110\108\121 \114\101\106\101\099\116 \111\110\099\101",function()local D local e local O=v.new(function(v,e)D=e end)local G=v.new(function(v,D)e=D end)local C=v.all({O;G});(expect(C:getStatus())).to.equal(v.Status.Started)D("\102\111\111","\098\097\114");(expect(C:getStatus())).to.equal(v.Status.Rejected)e("\098\097\122","\113\117\120")local R,m=p(C:_unwrap())local r,g,a=unpack(m,1,R);(expect(R)).to.equal(3);(expect(r)).to.equal(false);(expect(g)).to.equal("\102\111\111");(expect(a)).to.equal("\098\097\114")end)it("\115\104\111\117\108\100 \101\114\114\111\114 \105\102 \097 \110\111\110-\097\114\114\097\121 \116\097\098\108\101 \105\115 \112\097\115\115\101\100 \105\110",function()local D,e=pcall(function()v.all(v.new(function() end))end);(expect(D)).to.be.ok();(expect(e:find("\078\111\110\037-\112\114\111\109\105\115\101"))).to.be.ok()end)it("\115\104\111\117\108\100 \099\097\110\099\101\108 \112\101\110\100\105\110\103 \112\114\111\109\105\115\101\115 \105\102 \111\110\101 \114\101\106\101\099\116\115",function()local D=v.new(function() end);(expect((v.all({v.resolve(),v.reject();D})):getStatus())).to.equal(v.Status.Rejected);(expect(D:getStatus())).to.equal(v.Status.Cancelled)end)it("\115\104\111\117\108\100 \099\097\110\099\101\108 \112\114\111\109\105\115\101\115 \105\102 \105\116 \105\115 \099\097\110\099\101\108\108\101\100",function()local D=v.new(function() end)D:andThen(function() end)local e={v.new(function() end);v.new(function() end),D};(v.all(e)):cancel();(expect(e[1]:getStatus())).to.equal(v.Status.Cancelled);(expect(e[2]:getStatus())).to.equal(v.Status.Cancelled);(expect(e[3]:getStatus())).to.equal(v.Status.Started)end)end)describe("\080\114\111\109\105\115\101\046\102\111\108\100",function()it("\115\104\111\117\108\100 \114\101\116\117\114\110 \116\104\101 \105\110\105\116\105\097\108 \118\097\108\117\101 \105\110 \097 \112\114\111\109\105\115\101 \119\104\101\110 \116\104\101 \108\105\115\116 \105\115 \101\109\112\116\121",function()local D={}local e=v.fold({},function()error("\115\104\111\117\108\100 \110\111\116 \098\101 \099\097\108\108\101\100")end,D);(expect(v.is(e))).to.equal(true);(expect(e:getStatus())).to.equal(v.Status.Resolved);(expect(e:expect())).to.equal(D)end)it("\115\104\111\117\108\100 \097\099\099\101\112\116 \112\114\111\109\105\115\101\115 \105\110 \116\104\101 \108\105\115\116",function()local D local e=v.fold({v.new(function(v)D=v end),2;3},function(v,D)return v+D end,0)D(1);(expect(v.is(e))).to.equal(true);(expect(e:getStatus())).to.equal(v.Status.Resolved);(expect(e:expect())).to.equal(6)end)it("\115\104\111\117\108\100 \097\108\119\097\121\115 \114\101\116\117\114\110 \097 \112\114\111\109\105\115\101 \101\118\101\110 \105\102 \116\104\101 \108\105\115\116 \111\114 \114\101\100\117\099\101\114 \100\111\110\'\116 \117\115\101 \116\104\101\109",function()local D=v.fold({1,2,3},function(D,e,p)if p==2 then return(v.delay(1)):andThenReturn(D+e)else return D+e end end,0);(expect(v.is(D))).to.equal(true);(expect(D:getStatus())).to.equal(v.Status.Started)e(2);(expect(D:getStatus())).to.equal(v.Status.Resolved);(expect(D:expect())).to.equal(6)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \116\104\101 \102\105\114\115\116 \114\101\106\101\099\116\101\100 \112\114\111\109\105\115\101",function()local D="\102\111\111"local e=v.fold({1;2;3},function(e,p,O)if O==2 then return v.reject(D)else return e+p end end,0);(expect(v.is(e))).to.equal(true)local p,O=e:awaitStatus();(expect(p)).to.equal(v.Status.Rejected);(expect(O)).to.equal(D)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \116\104\101 \102\105\114\115\116 \099\097\110\099\101\108\101\100 \112\114\111\109\105\115\101",function()local D local e=v.fold({1,2,3},function(e,p,O)if O==1 then return e+p elseif O==2 then D=(v.delay(1)):andThenReturn(e+p)return D else error("\116\104\105\115 \115\104\111\117\108\100 \110\111\116 \114\117\110 \105\102 \116\104\101 \112\114\111\109\105\115\101 \105\115 \099\097\110\099\101\108\108\101\100")end end,0);(expect(v.is(e))).to.equal(true);(expect(e:getStatus())).to.equal(v.Status.Started)D:cancel();(expect(e:getStatus())).to.equal(v.Status.Cancelled)end)end)describe("\080\114\111\109\105\115\101\046\114\097\099\101",function()it("\115\104\111\117\108\100 \114\101\115\111\108\118\101 \119\105\116\104 \116\104\101 \102\105\114\115\116 \115\101\116\116\108\101\100 \118\097\108\117\101",function()local D=(v.race({v.resolve(1),v.resolve(2)})):andThen(function(v)(expect(v)).to.equal(1)end);(expect(D:getStatus())).to.equal(v.Status.Resolved)end)it("\115\104\111\117\108\100 \099\097\110\099\101\108 \111\116\104\101\114 \112\114\111\109\105\115\101\115",function()local D=v.new(function() end)D:andThen(function() end)local e={D;v.new(function() end),v.new(function(v)v(2)end)}local p=v.race(e);(expect(p:getStatus())).to.equal(v.Status.Resolved);(expect(p._values[1])).to.equal(2);(expect(e[1]:getStatus())).to.equal(v.Status.Started);(expect(e[2]:getStatus())).to.equal(v.Status.Cancelled);(expect(e[3]:getStatus())).to.equal(v.Status.Resolved)local O=v.new(function() end);(expect((v.race({v.reject(),v.resolve();O})):getStatus())).to.equal(v.Status.Rejected);(expect(O:getStatus())).to.equal(v.Status.Cancelled)end)it("\115\104\111\117\108\100 \101\114\114\111\114 \105\102 \097 \110\111\110-\097\114\114\097\121 \116\097\098\108\101 \105\115 \112\097\115\115\101\100 \105\110",function()local D,e=pcall(function()v.race(v.new(function() end))end);(expect(D)).to.be.ok();(expect(e:find("\078\111\110\037-\112\114\111\109\105\115\101"))).to.be.ok()end)it("\115\104\111\117\108\100 \099\097\110\099\101\108 \112\114\111\109\105\115\101\115 \105\102 \105\116 \105\115 \099\097\110\099\101\108\108\101\100",function()local D=v.new(function() end)D:andThen(function() end)local e={v.new(function() end);v.new(function() end),D};(v.race(e)):cancel();(expect(e[1]:getStatus())).to.equal(v.Status.Cancelled);(expect(e[2]:getStatus())).to.equal(v.Status.Cancelled);(expect(e[3]:getStatus())).to.equal(v.Status.Started)end)end)describe("\080\114\111\109\105\115\101\046\112\114\111\109\105\115\105\102\121",function()it("\115\104\111\117\108\100 \119\114\097\112 \102\117\110\099\116\105\111\110\115",function()local function D(v)return v+1 end local e=v.promisify(D)local p=e(1)local O,G=p:_unwrap();(expect(O)).to.equal(true);(expect(p:getStatus())).to.equal(v.Status.Resolved);(expect(G)).to.equal(2)end)it("\115\104\111\117\108\100 \099\097\116\099\104 \101\114\114\111\114\115 \097\102\116\101\114 \097 \121\105\101\108\100",function()local D=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")local e=v.promisify(function()D.Event:Wait()error("\101\114\114\111\114\116\101\120\116")end)local p=e();(expect(p:getStatus())).to.equal(v.Status.Started)D:Fire();(expect(p:getStatus())).to.equal(v.Status.Rejected);(expect((tostring(p._values[1])):find("\101\114\114\111\114\116\101\120\116"))).to.be.ok()end)end)describe("\080\114\111\109\105\115\101\046\116\097\112",function()it("\115\104\111\117\108\100 \116\104\114\101\097\100 \116\104\114\111\117\103\104 \118\097\108\117\101\115",function()local D,e;(((v.resolve(1)):andThen(function(v)return v+1 end)):tap(function(v)D=v return v+1 end)):andThen(function(v)e=v end);(expect(D)).to.equal(2);(expect(e)).to.equal(2)end)it("\115\104\111\117\108\100 \099\104\097\105\110 \111\110\116\111 \112\114\111\109\105\115\101\115",function()local D,e local p=((v.resolve(1)):tap(function()return v.new(function(v)D=v end)end)):andThen(function(v)e=v end);(expect(p:getStatus())).to.equal(v.Status.Started);(expect(e)).to.never.be.ok()D(1);(expect(p:getStatus())).to.equal(v.Status.Resolved);(expect(e)).to.equal(1)end)end)describe("\080\114\111\109\105\115\101\046\116\114\121",function()it("\115\104\111\117\108\100 \099\097\116\099\104 \115\121\110\099\104\114\111\110\111\117\115 \101\114\114\111\114\115",function()local D;(v.try(function()error("\101\114\114\111\114\116\101\120\116")end)):catch(function(v)D=tostring(v)end);(expect(D:find("\101\114\114\111\114\116\101\120\116"))).to.be.ok()end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \119\105\116\104 \101\114\114\111\114 \111\098\106\101\099\116\115",function()local D={}local e,p=(v.try(function()error(D)end)):_unwrap();(expect(e)).to.equal(false);(expect(p)).to.equal(D)end)it("\115\104\111\117\108\100 \099\097\116\099\104 \097\115\121\110\099\104\114\111\110\111\117\115 \101\114\114\111\114\115",function()local D=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")local e=v.try(function()D.Event:Wait()error("\101\114\114\111\114\116\101\120\116")end);(expect(e:getStatus())).to.equal(v.Status.Started)D:Fire();(expect(e:getStatus())).to.equal(v.Status.Rejected);(expect((tostring(e._values[1])):find("\101\114\114\111\114\116\101\120\116"))).to.be.ok()end)end)describe("\080\114\111\109\105\115\101\058\097\110\100\084\104\101\110\082\101\116\117\114\110",function()it("\115\104\111\117\108\100 \114\101\116\117\114\110 \116\104\101 \103\105\118\101\110 \118\097\108\117\101\115",function()local D,e;((v.resolve()):andThenReturn(1,2)):andThen(function(v,p)D=v e=p end);(expect(D)).to.equal(1);(expect(e)).to.equal(2)end)end)describe("\080\114\111\109\105\115\101\058\097\110\100\084\104\101\110\067\097\108\108",function()it("\115\104\111\117\108\100 \099\097\108\108 \116\104\101 \103\105\118\101\110 \102\117\110\099\116\105\111\110 \119\105\116\104 \097\114\103\117\109\101\110\116\115",function()local D,e;(v.resolve()):andThenCall(function(v,p)D=v e=p end,3,4);(expect(D)).to.equal(3);(expect(e)).to.equal(4)end)end)describe("\080\114\111\109\105\115\101\046\115\111\109\101",function()it("\115\104\111\117\108\100 \114\101\115\111\108\118\101 \111\110\099\101 \116\104\101 \103\111\097\108 \105\115 \114\101\097\099\104\101\100",function()local D=v.some({v.resolve(1);v.reject(),v.resolve(2)},2);(expect(D:getStatus())).to.equal(v.Status.Resolved);(expect(D._values[1][1])).to.equal(1);(expect(D._values[1][2])).to.equal(2)end)it("\115\104\111\117\108\100 \101\114\114\111\114 \105\102 \116\104\101 \103\111\097\108 \099\097\110\'\116 \098\101 \114\101\097\099\104\101\100",function()(expect((v.some({v.resolve(),v.reject()},2)):getStatus())).to.equal(v.Status.Rejected)local D local e=v.some({v.resolve(),v.new(function(v,e)D=e end)},2);(expect(e:getStatus())).to.equal(v.Status.Started)D("\102\111\111");(expect(e:getStatus())).to.equal(v.Status.Rejected);(expect(e._values[1])).to.equal("\102\111\111")end)it("\115\104\111\117\108\100 \099\097\110\099\101\108 \112\101\110\100\105\110\103 \080\114\111\109\105\115\101\115 \111\110\099\101 \116\104\101 \103\111\097\108 \105\115 \114\101\097\099\104\101\100",function()local D local e=v.new(function() end)local p=v.new(function(v)D=v end)local O=v.some({e,p;v.resolve()},2);(expect(O:getStatus())).to.equal(v.Status.Started);(expect(e:getStatus())).to.equal(v.Status.Started);(expect(p:getStatus())).to.equal(v.Status.Started)D();(expect(O:getStatus())).to.equal(v.Status.Resolved);(expect(e:getStatus())).to.equal(v.Status.Cancelled);(expect(p:getStatus())).to.equal(v.Status.Resolved)end)it("\115\104\111\117\108\100 \101\114\114\111\114 \105\102 \112\097\115\115\101\100 \097 \110\111\110-\110\117\109\098\101\114",function()(expect(function()v.some({},"\110\111\110-\110\117\109\098\101\114")end)).to.throw()end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \097\110 \101\109\112\116\121 \097\114\114\097\121 \105\102 \097\109\111\117\110\116 \105\115 \048",function()local D=v.some({v.resolve(2)},0);(expect(D:getStatus())).to.equal(v.Status.Resolved);(expect(#D._values[1])).to.equal(0)end)it("\115\104\111\117\108\100 \110\111\116 \114\101\116\117\114\110 \101\120\116\114\097 \118\097\108\117\101\115",function()local D=v.some({v.resolve(1),v.resolve(2);v.resolve(3),v.resolve(4)},2);(expect(D:getStatus())).to.equal(v.Status.Resolved);(expect(#D._values[1])).to.equal(2);(expect(D._values[1][1])).to.equal(1);(expect(D._values[1][2])).to.equal(2)end)it("\115\104\111\117\108\100 \099\097\110\099\101\108 \112\114\111\109\105\115\101\115 \105\102 \105\116 \105\115 \099\097\110\099\101\108\108\101\100",function()local D=v.new(function() end)D:andThen(function() end)local e={v.new(function() end);v.new(function() end),D};(v.some(e,3)):cancel();(expect(e[1]:getStatus())).to.equal(v.Status.Cancelled);(expect(e[2]:getStatus())).to.equal(v.Status.Cancelled);(expect(e[3]:getStatus())).to.equal(v.Status.Started)end)describe("\080\114\111\109\105\115\101\046\097\110\121",function()it("\115\104\111\117\108\100 \114\101\116\117\114\110 \116\104\101 \118\097\108\117\101 \100\105\114\101\099\116\108\121",function()local D=v.any({v.reject(),v.reject();v.resolve(1)});(expect(D:getStatus())).to.equal(v.Status.Resolved);(expect(D._values[1])).to.equal(1)end)it("\115\104\111\117\108\100 \101\114\114\111\114 \105\102 \097\108\108 \097\114\101 \114\101\106\101\099\116\101\100",function()(expect((v.any({v.reject(),v.reject();v.reject()})):getStatus())).to.equal(v.Status.Rejected)end)end)end)describe("\080\114\111\109\105\115\101\046\097\108\108\083\101\116\116\108\101\100",function()it("\115\104\111\117\108\100 \114\101\115\111\108\118\101 \119\105\116\104 \097\110 \097\114\114\097\121 \111\102 \080\114\111\109\105\115\101\083\116\097\116\117\115\101\115",function()local D local e=v.allSettled({v.resolve();v.reject(),v.resolve(),v.new(function(v,e)D=e end)});(expect(e:getStatus())).to.equal(v.Status.Started)D();(expect(e:getStatus())).to.equal(v.Status.Resolved);(expect(e._values[1][1])).to.equal(v.Status.Resolved);(expect(e._values[1][2])).to.equal(v.Status.Rejected);(expect(e._values[1][3])).to.equal(v.Status.Resolved);(expect(e._values[1][4])).to.equal(v.Status.Rejected)end)it("\115\104\111\117\108\100 \099\097\110\099\101\108 \112\114\111\109\105\115\101\115 \105\102 \105\116 \105\115 \099\097\110\099\101\108\108\101\100",function()local D=v.new(function() end)D:andThen(function() end)local e={v.new(function() end);v.new(function() end);D};(v.allSettled(e)):cancel();(expect(e[1]:getStatus())).to.equal(v.Status.Cancelled);(expect(e[2]:getStatus())).to.equal(v.Status.Cancelled);(expect(e[3]:getStatus())).to.equal(v.Status.Started)end)end)describe("\080\114\111\109\105\115\101\058\097\119\097\105\116",function()it("\115\104\111\117\108\100 \114\101\116\117\114\110 \116\104\101 \099\111\114\114\101\099\116 \118\097\108\117\101\115",function()local D=v.resolve(5,6,nil,7)local e,p,O,G,C=D:await();(expect(e)).to.equal(true);(expect(p)).to.equal(5);(expect(O)).to.equal(6);(expect(G)).to.equal(nil);(expect(C)).to.equal(7)end)it("\115\104\111\117\108\100 \119\111\114\107 \105\102 \121\105\101\108\100\105\110\103 \105\115 \110\101\101\100\101\100",function()local D=false task.spawn(function()local e,p=(v.delay(1)):await();(expect(type(p))).to.equal("\110\117\109\098\101\114")D=true end)e(2);(expect(D)).to.equal(true)end)end)describe("\080\114\111\109\105\115\101\058\101\120\112\101\099\116",function()it("\115\104\111\117\108\100 \116\104\114\111\119 \116\104\101 \099\111\114\114\101\099\116 \118\097\108\117\101\115",function()local D={}local e=v.reject(D)local p,O=pcall(function()e:expect()end);(expect(p)).to.equal(false);(expect(O)).to.equal(D)end)end)describe("\080\114\111\109\105\115\101\058\110\111\119",function()it("\115\104\111\117\108\100 \114\101\115\111\108\118\101 \105\102 \116\104\101 \080\114\111\109\105\115\101 \105\115 \114\101\115\111\108\118\101\100",function()local D,e=((v.resolve("\102\111\111")):now()):_unwrap();(expect(D)).to.equal(true);(expect(e)).to.equal("\102\111\111")end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \105\102 \116\104\101 \080\114\111\109\105\115\101 \105\115 \110\111\116 \114\101\115\111\108\118\101\100",function()local D,e=((v.new(function() end)):now()):_unwrap();(expect(D)).to.equal(false);(expect(v.Error.isKind(e,"\078\111\116\082\101\115\111\108\118\101\100\073\110\084\105\109\101"))).to.equal(true)end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \119\105\116\104 \097 \099\117\115\116\111\109 \114\101\106\101\099\116\105\111\110 \118\097\108\117\101",function()local D,e=((v.new(function() end)):now("\102\111\111")):_unwrap();(expect(D)).to.equal(false);(expect(e)).to.equal("\102\111\111")end)end)describe("\080\114\111\109\105\115\101\046\101\097\099\104",function()it("\115\104\111\117\108\100 \105\116\101\114\097\116\101",function()local D,e=(v.each({"\102\111\111","\098\097\114";"\098\097\122";"\113\117\120"},function(...)return{...}end)):_unwrap();(expect(D)).to.equal(true);(expect(e[1][1])).to.equal("\102\111\111");(expect(e[1][2])).to.equal(1);(expect(e[2][1])).to.equal("\098\097\114");(expect(e[2][2])).to.equal(2);(expect(e[3][1])).to.equal("\098\097\122");(expect(e[3][2])).to.equal(3);(expect(e[4][1])).to.equal("\113\117\120");(expect(e[4][2])).to.equal(4)end)it("\115\104\111\117\108\100 \105\116\101\114\097\116\101 \115\101\114\105\097\108\108\121",function()local D={}local e={}local p=v.each({"\102\111\111","\098\097\114","\098\097\122"},function(p,O)e[O]=(e[O]or 0)+1 return v.new(function(v)table.insert(D,function()v(p:upper())end)end)end);(expect(p:getStatus())).to.equal(v.Status.Started);(expect(#D)).to.equal(1);(expect(e[1])).to.equal(1);(expect(e[2])).to.never.be.ok();(table.remove(D,1))();(expect(p:getStatus())).to.equal(v.Status.Started);(expect(#D)).to.equal(1);(expect(e[1])).to.equal(1);(expect(e[2])).to.equal(1);(expect(e[3])).to.never.be.ok();(table.remove(D,1))();(expect(p:getStatus())).to.equal(v.Status.Started);(expect(e[1])).to.equal(1);(expect(e[2])).to.equal(1);(expect(e[3])).to.equal(1);(table.remove(D,1))();(expect(p:getStatus())).to.equal(v.Status.Resolved);(expect(type(p._values[1]))).to.equal("\116\097\098\108\101");(expect(type(p._values[2]))).to.equal("\110\105\108")local O=p._values[1];(expect(O[1])).to.equal("\070\079\079");(expect(O[2])).to.equal("\066\065\082");(expect(O[3])).to.equal("\066\065\090")end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \119\105\116\104 \116\104\101 \118\097\108\117\101 \105\102 \116\104\101 \112\114\101\100\105\099\097\116\101 \112\114\111\109\105\115\101 \114\101\106\101\099\116\115",function()local D=v.each({1,2;3},function()return v.reject("\102\111\111\098\097\114")end);(expect(D:getStatus())).to.equal(v.Status.Rejected);(expect(D._values[1])).to.equal("\102\111\111\098\097\114")end)it("\115\104\111\117\108\100 \097\108\108\111\119 \080\114\111\109\105\115\101\115 \116\111 \098\101 \105\110 \116\104\101 \108\105\115\116 \097\110\100 \119\097\105\116 \119\104\101\110 \105\116 \103\101\116\115 \116\111 \116\104\101\109",function()local D local e=v.new(function(v)D=v end)local p=v.each({e},function(v)return v*2 end);(expect(p:getStatus())).to.equal(v.Status.Started)D(2);(expect(p:getStatus())).to.equal(v.Status.Resolved);(expect(p._values[1][1])).to.equal(4)end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \119\105\116\104 \116\104\101 \118\097\108\117\101 \105\102 \097 \080\114\111\109\105\115\101 \102\114\111\109 \116\104\101 \108\105\115\116 \114\101\106\101\099\116\115",function()local D=false local e=v.each({1,2,v.reject("\102\111\111\098\097\114")},function(v)D=true return"\110\101\118\101\114"end);(expect(e:getStatus())).to.equal(v.Status.Rejected);(expect(e._values[1])).to.equal("\102\111\111\098\097\114");(expect(D)).to.equal(false)end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \105\109\109\101\100\105\097\116\101\108\121 \105\102 \116\104\101\114\101\'\115 \097 \099\097\110\099\101\108\108\101\100 \080\114\111\109\105\115\101 \105\110 \116\104\101 \108\105\115\116 \105\110\105\116\105\097\108\108\121",function()local D=v.new(function() end)D:cancel()local e=false local p=v.each({1;2,D},function()e=true end);(expect(p:getStatus())).to.equal(v.Status.Rejected);(expect(e)).to.equal(false);(expect(p._values[1].kind)).to.equal(v.Error.Kind.AlreadyCancelled)end)it("\115\104\111\117\108\100 \115\116\111\112 \105\116\101\114\097\116\105\111\110 \105\102 \080\114\111\109\105\115\101\046\101\097\099\104 \105\115 \099\097\110\099\101\108\108\101\100",function()local D={}local e=v.each({"\102\111\111";"\098\097\114";"\098\097\122"},function(e,p)D[p]=(D[p]or 0)+1 return v.new(function() end)end);(expect(e:getStatus())).to.equal(v.Status.Started);(expect(D[1])).to.equal(1);(expect(D[2])).to.never.be.ok()e:cancel();(expect(e:getStatus())).to.equal(v.Status.Cancelled);(expect(D[1])).to.equal(1);(expect(D[2])).to.never.be.ok()end)it("\115\104\111\117\108\100 \099\097\110\099\101\108 \116\104\101 \080\114\111\109\105\115\101 \114\101\116\117\114\110\101\100 \102\114\111\109 \116\104\101 \112\114\101\100\105\099\097\116\101 \105\102 \080\114\111\109\105\115\101\046\101\097\099\104 \105\115 \099\097\110\099\101\108\108\101\100",function()local D local e=v.each({"\102\111\111","\098\097\114";"\098\097\122"},function(e,p)D=v.new(function() end)return D end)e:cancel();(expect(D:getStatus())).to.equal(v.Status.Cancelled)end)it("\115\104\111\117\108\100 \099\097\110\099\101\108 \080\114\111\109\105\115\101\115 \105\110 \116\104\101 \108\105\115\116 \105\102 \080\114\111\109\105\115\101\046\101\097\099\104 \105\115 \099\097\110\099\101\108\108\101\100",function()local D=v.new(function() end)local e=v.each({D},function() end)e:cancel();(expect(D:getStatus())).to.equal(v.Status.Cancelled)end)end)describe("\080\114\111\109\105\115\101\046\114\101\116\114\121",function()it("\115\104\111\117\108\100 \114\101\116\114\121 \078 \116\105\109\101\115",function()local D=0 local e=v.retry(function(e)(expect(e)).to.equal("\102\111\111")D=D+1 if D==5 then return v.resolve("\111\107")end return v.reject("\102\097\105\108")end,5,"\102\111\111");(expect(e:getStatus())).to.equal(v.Status.Resolved);(expect(e._values[1])).to.equal("\111\107")end)it("\115\104\111\117\108\100 \114\101\106\101\099\116 \105\102 \116\104\114\101\115\104\111\108\100 \105\115 \101\120\099\101\101\100\101\100",function()local D=v.retry(function()return v.reject("\102\097\105\108")end,5);(expect(D:getStatus())).to.equal(v.Status.Rejected);(expect(D._values[1])).to.equal("\102\097\105\108")end)end)describe("\080\114\111\109\105\115\101\046\114\101\116\114\121\087\105\116\104\068\101\108\097\121",function()it("\115\104\111\117\108\100 \114\101\116\114\121 \097\102\116\101\114 \097 \100\101\108\097\121",function()local D=0 local p=v.retryWithDelay(function(e)(expect(e)).to.equal("\102\111\111")D=D+1 if D==3 then return v.resolve("\111\107")end return v.reject("\102\097\105\108")end,3,10,"\102\111\111");(expect(D)).to.equal(1)e(11);(expect(D)).to.equal(2)e(11);(expect(D)).to.equal(3);(expect(p:getStatus())).to.equal(v.Status.Resolved);(expect(p._values[1])).to.equal("\111\107")end)end)describe("\080\114\111\109\105\115\101\046\102\114\111\109\069\118\101\110\116",function()it("\115\104\111\117\108\100 \099\111\110\118\101\114\116 \097 \080\114\111\109\105\115\101 \105\110\116\111 \097\110 \101\118\101\110\116",function()local D=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")local e=v.fromEvent(D.Event);(expect(e:getStatus())).to.equal(v.Status.Started)D:Fire("\102\111\111");(expect(e:getStatus())).to.equal(v.Status.Resolved);(expect(e._values[1])).to.equal("\102\111\111")end)it("\115\104\111\117\108\100 \099\111\110\118\101\114\116 \097 \080\114\111\109\105\115\101 \105\110\116\111 \097\110 \101\118\101\110\116 \119\105\116\104 \116\104\101 \112\114\101\100\105\099\097\116\101",function()local D=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")local e=v.fromEvent(D.Event,function(v)return v=="\102\111\111"end);(expect(e:getStatus())).to.equal(v.Status.Started)D:Fire("\098\097\114");(expect(e:getStatus())).to.equal(v.Status.Started)D:Fire("\102\111\111");(expect(e:getStatus())).to.equal(v.Status.Resolved);(expect(e._values[1])).to.equal("\102\111\111")end)end)describe("\080\114\111\109\105\115\101\046\105\115",function()it("\115\104\111\117\108\100 \119\111\114\107 \119\105\116\104 \099\117\114\114\101\110\116 \118\101\114\115\105\111\110",function()local D=v.resolve(1);(expect(v.is(D))).to.equal(true)end)it("\115\104\111\117\108\100 \119\111\114\107 \119\105\116\104 \097\110\121 \111\098\106\101\099\116 \119\105\116\104 \097\110 \097\110\100\084\104\101\110",function()local D={andThen=function()return 1 end};(expect(v.is(D))).to.equal(true)end)it("\115\104\111\117\108\100 \119\111\114\107 \119\105\116\104 \111\108\100\101\114 \112\114\111\109\105\115\101\115",function()local D={}D.prototype={}D.__index=D.prototype function D.prototype.andThen(v) end local e=setmetatable({},D);(expect(v.is(e))).to.equal(true)end)end)end
return function()
	local Promise = require(script.Parent)
	Promise.TEST = true

	local timeEvent = Instance.new("BindableEvent")
	Promise._timeEvent = timeEvent.Event

	local advanceTime
	do
		local injectedPromiseTime = 0

		Promise._getTime = function()
			return injectedPromiseTime
		end

		function advanceTime(delta)
			delta = delta or (1 / 60)

			injectedPromiseTime = injectedPromiseTime + delta
			timeEvent:Fire(delta)
		end
	end

	local function pack(...)
		local len = select("#", ...)

		return len, { ... }
	end

	describe("Promise.Status", function()
		it("should error if indexing nil value", function()
			expect(function()
				local _ = Promise.Status.wrong
			end).to.throw()
		end)
	end)

	describe("Unhandled rejection signal", function()
		it("should call unhandled rejection callbacks", function()
			local badPromise = Promise.new(function(_resolve, reject)
				reject(1, 2)
			end)

			local callCount = 0

			local function callback(promise, rejectionA, rejectionB)
				callCount += 1

				expect(promise).to.equal(badPromise)
				expect(rejectionA).to.equal(1)
				expect(rejectionB).to.equal(2)
			end

			local unregister = Promise.onUnhandledRejection(callback)

			advanceTime()

			expect(callCount).to.equal(1)

			unregister()

			Promise.new(function(_resolve, reject)
				reject(3, 4)
			end)

			advanceTime()

			expect(callCount).to.equal(1)
		end)
	end)

	describe("Promise.new", function()
		it("should instantiate with a callback", function()
			local promise = Promise.new(function() end)

			expect(promise).to.be.ok()
		end)

		it("should invoke the given callback with resolve and reject", function()
			local callCount = 0
			local resolveArg
			local rejectArg

			local promise = Promise.new(function(resolve, reject)
				callCount = callCount + 1
				resolveArg = resolve
				rejectArg = reject
			end)

			expect(promise).to.be.ok()

			expect(callCount).to.equal(1)
			expect(resolveArg).to.be.a("function")
			expect(rejectArg).to.be.a("function")
			expect(promise:getStatus()).to.equal(Promise.Status.Started)
		end)

		it("should resolve promises on resolve()", function()
			local callCount = 0

			local promise = Promise.new(function(resolve)
				callCount = callCount + 1
				resolve()
			end)

			expect(promise).to.be.ok()
			expect(callCount).to.equal(1)
			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
		end)

		it("should reject promises on reject()", function()
			local callCount = 0

			local promise = Promise.new(function(resolve, reject)
				callCount = callCount + 1
				reject()
			end)

			expect(promise).to.be.ok()
			expect(callCount).to.equal(1)
			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
		end)

		it("should reject on error in callback", function()
			local callCount = 0

			local promise = Promise.new(function()
				callCount = callCount + 1
				error("hahah")
			end)

			expect(promise).to.be.ok()
			expect(callCount).to.equal(1)
			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(tostring(promise._values[1]):find("hahah")).to.be.ok()

			-- Loosely check for the pieces of the stack trace we expect
			expect(tostring(promise._values[1]):find("init.spec")).to.be.ok()
			expect(tostring(promise._values[1]):find("runExecutor")).to.be.ok()
		end)

		it("should work with C functions", function()
			expect(function()
				Promise.new(tick):andThen(tick)
			end).to.never.throw()
		end)

		it("should have a nice tostring", function()
			expect(tostring(Promise.resolve()):gmatch("Promise(Resolved)")).to.be.ok()
		end)

		it("should allow yielding", function()
			local bindable = Instance.new("BindableEvent")
			local promise = Promise.new(function(resolve)
				bindable.Event:Wait()
				resolve(5)
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			bindable:Fire()
			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(promise._values[1]).to.equal(5)
		end)

		it("should preserve stack traces of resolve-chained promises", function()
			local function nestedCall(text)
				error(text)
			end

			local promise = Promise.new(function(resolve)
				resolve(Promise.new(function()
					nestedCall("sample text")
				end))
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)

			local trace = tostring(promise._values[1])
			expect(trace:find("sample text")).to.be.ok()
			expect(trace:find("nestedCall")).to.be.ok()
			expect(trace:find("runExecutor")).to.be.ok()
			expect(trace:find("runPlanNode")).to.be.ok()
			expect(
				trace:find("...Rejected because it was chained to the following Promise, which encountered an error:")
			).to.be.ok()
		end)

		it("should report errors from Promises with _error (< v2)", function()
			local oldPromise = Promise.reject()
			oldPromise._error = "Sample error"

			local newPromise = Promise.resolve():andThenReturn(oldPromise)

			expect(newPromise:getStatus()).to.equal(Promise.Status.Rejected)

			local trace = tostring(newPromise._values[1])
			expect(trace:find("Sample error")).to.be.ok()
			expect(
				trace:find("...Rejected because it was chained to the following Promise, which encountered an error:")
			).to.be.ok()
			expect(trace:find("%[No stack trace available")).to.be.ok()
		end)

		it("should allow callable tables", function()
			local promise = Promise.new(setmetatable({}, {
				__call = function(_, resolve)
					resolve(1)
				end,
			}))

			local called = false
			promise:andThen(setmetatable({}, {
				__call = function(_, var)
					expect(var).to.equal(1)
					called = true
				end,
			}))

			expect(called).to.equal(true)
		end)

		itSKIP("should close the thread after resolve", function()
			local count = 0
			Promise.new(function(resolve)
				count += 1
				resolve()
				Promise.delay(1):await()
				count += 1
			end)

			task.wait(1)

			expect(count).to.equal(1)
		end)
	end)

	describe("Promise.defer", function()
		it("should execute after the time event", function()
			local callCount = 0
			local promise = Promise.defer(function(resolve, reject, onCancel, nothing)
				expect(type(resolve)).to.equal("function")
				expect(type(reject)).to.equal("function")
				expect(type(onCancel)).to.equal("function")
				expect(type(nothing)).to.equal("nil")

				callCount = callCount + 1

				resolve("foo")
			end)

			expect(callCount).to.equal(0)
			expect(promise:getStatus()).to.equal(Promise.Status.Started)

			advanceTime()
			expect(callCount).to.equal(1)
			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)

			advanceTime()
			expect(callCount).to.equal(1)
		end)
	end)

	describe("Promise.delay", function()
		it("should schedule promise resolution", function()
			local promise = Promise.delay(1)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)

			advanceTime()
			expect(promise:getStatus()).to.equal(Promise.Status.Started)

			advanceTime(1)
			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
		end)

		it("should allow for delays to be cancelled", function()
			local promise = Promise.delay(2)

			Promise.delay(1):andThen(function()
				promise:cancel()
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			advanceTime()
			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			advanceTime(1)
			expect(promise:getStatus()).to.equal(Promise.Status.Cancelled)
			advanceTime(1)
		end)
	end)

	describe("Promise.resolve", function()
		it("should immediately resolve with a value", function()
			local promise = Promise.resolve(5, 6)

			expect(promise).to.be.ok()
			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(promise._values[1]).to.equal(5)
			expect(promise._values[2]).to.equal(6)
		end)

		it("should chain onto passed promises", function()
			local promise = Promise.resolve(Promise.new(function(_, reject)
				reject(7)
			end))

			expect(promise).to.be.ok()
			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(promise._values[1]).to.equal(7)
		end)
	end)

	describe("Promise.reject", function()
		it("should immediately reject with a value", function()
			local promise = Promise.reject(6, 7)

			expect(promise).to.be.ok()
			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(promise._values[1]).to.equal(6)
			expect(promise._values[2]).to.equal(7)
		end)

		it("should pass a promise as-is as an error", function()
			local innerPromise = Promise.new(function(resolve)
				resolve(6)
			end)

			local promise = Promise.reject(innerPromise)

			expect(promise).to.be.ok()
			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(promise._values[1]).to.equal(innerPromise)
		end)
	end)

	describe("Promise:andThen", function()
		it("should allow yielding", function()
			local bindable = Instance.new("BindableEvent")
			local promise = Promise.resolve():andThen(function()
				bindable.Event:Wait()
				return 5
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			bindable:Fire()
			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(promise._values[1]).to.equal(5)
		end)

		it("should run andThens on a new thread", function()
			local bindable = Instance.new("BindableEvent")

			local resolve
			local parentPromise = Promise.new(function(_resolve)
				resolve = _resolve
			end)

			local deadlockedPromise = parentPromise:andThen(function()
				bindable.Event:Wait()
				return 5
			end)

			local successfulPromise = parentPromise:andThen(function()
				return "foo"
			end)

			expect(parentPromise:getStatus()).to.equal(Promise.Status.Started)
			resolve()
			expect(successfulPromise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(successfulPromise._values[1]).to.equal("foo")
			expect(deadlockedPromise:getStatus()).to.equal(Promise.Status.Started)
		end)

		it("should chain onto resolved promises", function()
			local args
			local argsLength
			local callCount = 0
			local badCallCount = 0

			local promise = Promise.resolve(5)

			local chained = promise:andThen(function(...)
				argsLength, args = pack(...)
				callCount = callCount + 1
			end, function()
				badCallCount = badCallCount + 1
			end)

			expect(badCallCount).to.equal(0)

			expect(callCount).to.equal(1)
			expect(argsLength).to.equal(1)
			expect(args[1]).to.equal(5)

			expect(promise).to.be.ok()
			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(promise._values[1]).to.equal(5)

			expect(chained).to.be.ok()
			expect(chained).never.to.equal(promise)
			expect(chained:getStatus()).to.equal(Promise.Status.Resolved)
			expect(#chained._values).to.equal(0)
		end)

		it("should chain onto rejected promises", function()
			local args
			local argsLength
			local callCount = 0
			local badCallCount = 0

			local promise = Promise.reject(5)

			local chained = promise:andThen(function(...)
				badCallCount = badCallCount + 1
			end, function(...)
				argsLength, args = pack(...)
				callCount = callCount + 1
			end)

			expect(badCallCount).to.equal(0)

			expect(callCount).to.equal(1)
			expect(argsLength).to.equal(1)
			expect(args[1]).to.equal(5)

			expect(promise).to.be.ok()
			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(promise._values[1]).to.equal(5)

			expect(chained).to.be.ok()
			expect(chained).never.to.equal(promise)
			expect(chained:getStatus()).to.equal(Promise.Status.Resolved)
			expect(#chained._values).to.equal(0)
		end)

		it("should reject on error in callback", function()
			local callCount = 0

			local promise = Promise.resolve(1):andThen(function()
				callCount = callCount + 1
				error("hahah")
			end)

			expect(promise).to.be.ok()
			expect(callCount).to.equal(1)
			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(tostring(promise._values[1]):find("hahah")).to.be.ok()

			-- Loosely check for the pieces of the stack trace we expect
			expect(tostring(promise._values[1]):find("init.spec")).to.be.ok()
			expect(tostring(promise._values[1]):find("runExecutor")).to.be.ok()
		end)

		it("should chain onto asynchronously resolved promises", function()
			local args
			local argsLength
			local callCount = 0
			local badCallCount = 0

			local startResolution
			local promise = Promise.new(function(resolve)
				startResolution = resolve
			end)

			local chained = promise:andThen(function(...)
				args = { ... }
				argsLength = select("#", ...)
				callCount = callCount + 1
			end, function()
				badCallCount = badCallCount + 1
			end)

			expect(callCount).to.equal(0)
			expect(badCallCount).to.equal(0)

			startResolution(6)

			expect(badCallCount).to.equal(0)

			expect(callCount).to.equal(1)
			expect(argsLength).to.equal(1)
			expect(args[1]).to.equal(6)

			expect(promise).to.be.ok()
			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(promise._values[1]).to.equal(6)

			expect(chained).to.be.ok()
			expect(chained).never.to.equal(promise)
			expect(chained:getStatus()).to.equal(Promise.Status.Resolved)
			expect(#chained._values).to.equal(0)
		end)

		it("should chain onto asynchronously rejected promises", function()
			local args
			local argsLength
			local callCount = 0
			local badCallCount = 0

			local startResolution
			local promise = Promise.new(function(_, reject)
				startResolution = reject
			end)

			local chained = promise:andThen(function()
				badCallCount = badCallCount + 1
			end, function(...)
				args = { ... }
				argsLength = select("#", ...)
				callCount = callCount + 1
			end)

			expect(callCount).to.equal(0)
			expect(badCallCount).to.equal(0)

			startResolution(6)

			expect(badCallCount).to.equal(0)

			expect(callCount).to.equal(1)
			expect(argsLength).to.equal(1)
			expect(args[1]).to.equal(6)

			expect(promise).to.be.ok()
			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(promise._values[1]).to.equal(6)

			expect(chained).to.be.ok()
			expect(chained).never.to.equal(promise)
			expect(chained:getStatus()).to.equal(Promise.Status.Resolved)
			expect(#chained._values).to.equal(0)
		end)

		it("should propagate errors through multiple levels", function()
			local x, y, z
			Promise.new(function(resolve, reject)
				reject(1, 2, 3)
			end):andThen(function() end):catch(function(a, b, c)
				x, y, z = a, b, c
			end)

			expect(x).to.equal(1)
			expect(y).to.equal(2)
			expect(z).to.equal(3)
		end)

		it("should not call queued callbacks from a cancelled sub-promise", function()
			local resolve
			local count = 0

			local root = Promise.new(function(r)
				resolve = r
			end)

			root:andThen(function()
				count += 1
			end)

			root
				:andThen(function()
					count += 1
				end)
				:cancel()

			resolve("foo")

			expect(count).to.equal(1)
		end)
	end)

	describe("Promise:cancel", function()
		it("should mark promises as cancelled and not resolve or reject them", function()
			local callCount = 0
			local finallyCallCount = 0
			local promise = Promise.new(function() end)
				:andThen(function()
					callCount = callCount + 1
				end)
				:finally(function()
					finallyCallCount = finallyCallCount + 1
				end)

			promise:cancel()
			promise:cancel() -- Twice to check call counts

			expect(callCount).to.equal(0)
			expect(finallyCallCount).to.equal(1)
			expect(promise:getStatus()).to.equal(Promise.Status.Cancelled)
		end)

		it("should call the cancellation hook once", function()
			local callCount = 0

			local promise = Promise.new(function(resolve, reject, onCancel)
				onCancel(function()
					callCount = callCount + 1
				end)
			end)

			promise:cancel()
			promise:cancel() -- Twice to check call count

			expect(callCount).to.equal(1)
		end)

		it("should propagate cancellations", function()
			local promise = Promise.new(function() end)

			local consumer1 = promise:andThen()
			local consumer2 = promise:andThen()

			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			expect(consumer1:getStatus()).to.equal(Promise.Status.Started)
			expect(consumer2:getStatus()).to.equal(Promise.Status.Started)

			consumer1:cancel()

			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			expect(consumer1:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(consumer2:getStatus()).to.equal(Promise.Status.Started)

			consumer2:cancel()

			expect(promise:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(consumer1:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(consumer2:getStatus()).to.equal(Promise.Status.Cancelled)
		end)

		it("should affect downstream promises", function()
			local promise = Promise.new(function() end)
			local consumer = promise:andThen()

			promise:cancel()

			expect(consumer:getStatus()).to.equal(Promise.Status.Cancelled)
		end)

		it("should track consumers", function()
			local pending = Promise.new(function() end)
			local p0 = Promise.resolve()
			local p1 = p0:andThen(function()
				return pending
			end)
			local p2 = Promise.new(function(resolve)
				resolve(p1)
			end)
			local p3 = p2:andThen(function() end)

			expect(p1._parent).to.never.equal(p0)
			expect(p2._parent).to.never.equal(p1)
			expect(p2._consumers[p3]).to.be.ok()
			expect(p3._parent).to.equal(p2)
		end)

		it("should cancel resolved pending promises", function()
			local p1 = Promise.new(function() end)

			local p2 = Promise.new(function(resolve)
				resolve(p1)
			end):finally(function() end)

			p2:cancel()

			expect(p1._status).to.equal(Promise.Status.Cancelled)
			expect(p2._status).to.equal(Promise.Status.Cancelled)
		end)

		it("should close the promise thread", function()
			local count = 0
			local promise = Promise.new(function()
				count += 1
				Promise.delay(1):await()
				count += 1
			end)

			promise:cancel()
			advanceTime(2)

			expect(count).to.equal(1)
		end)
	end)

	describe("Promise:finally", function()
		it("should be called upon resolve, reject, or cancel", function()
			local callCount = 0

			local function finally()
				callCount = callCount + 1
			end

			-- Resolved promise
			Promise.new(function(resolve, reject)
				resolve()
			end):finally(finally)

			-- Chained promise
			Promise.resolve():andThen(function() end):finally(finally):finally(finally)

			-- Rejected promise
			Promise.reject():finally(finally)

			local cancelledPromise = Promise.new(function() end):finally(finally)
			cancelledPromise:cancel()

			expect(callCount).to.equal(5)
		end)

		it("should not forward return values", function()
			local value

			Promise.resolve(2)
				:finally(function()
					return 1
				end)
				:andThen(function(v)
					value = v
				end)

			expect(value).to.equal(2)
		end)

		it("should not consume rejections", function()
			local catchRan = false
			local thenRan = false
			Promise.reject(5)
				:finally(function()
					return 42
				end)
				:andThen(function()
					thenRan = true
				end)
				:catch(function(value)
					catchRan = true
					expect(value).to.equal(5)
				end)

			expect(catchRan).to.equal(true)
			expect(thenRan).to.equal(false)
		end)

		it("should wait for returned promises", function()
			local resolve
			local promise = Promise.reject("foo"):finally(function()
				return Promise.new(function(r)
					resolve = r
				end)
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)

			resolve()

			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			local _, value = promise:_unwrap()
			expect(value).to.equal("foo")
		end)

		it("should reject with a returned rejected promise's value", function()
			local reject
			local promise = Promise.reject("foo"):finally(function()
				return Promise.new(function(_, r)
					reject = r
				end)
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)

			reject("bar")

			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			local _, value = promise:_unwrap()
			expect(value).to.equal("bar")
		end)

		it("should reject when handler errors", function()
			local errorValue = {}
			local promise = Promise.reject("bar"):finally(function()
				error(errorValue)
			end)

			local ok, value = promise:_unwrap()

			expect(ok).to.equal(false)
			expect(value).to.equal(errorValue)
		end)

		it("should not prevent cancellation", function()
			local promise = Promise.new(function() end)

			local finallyRan = false
			promise:finally(function()
				finallyRan = true
			end)

			local consumer = promise:andThen(function() end)

			consumer:cancel()

			expect(promise:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(finallyRan).to.equal(true)
		end)

		it("should propagate cancellation downwards", function()
			local finallyRan = false
			local andThenRan = false
			local root = Promise.new(function() end)

			local consumer = root:finally(function()
				finallyRan = true
			end)

			root:cancel()

			expect(root:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(consumer:getStatus()).to.equal(Promise.Status.Cancelled)

			expect(finallyRan).to.equal(true)
			expect(andThenRan).to.equal(false)
		end)

		it("should propagate cancellation upwards", function()
			local finallyRan = false
			local andThenRan = false
			local root = Promise.new(function() end)

			local consumer = root:finally(function()
				finallyRan = true
			end)

			consumer:cancel()

			expect(root:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(consumer:getStatus()).to.equal(Promise.Status.Cancelled)

			expect(finallyRan).to.equal(true)
			expect(andThenRan).to.equal(false)
		end)

		it("should cancel returned promise if cancelled", function()
			local internal = Promise.new(function() end)

			local promise = Promise.resolve():finally(function()
				return internal
			end)

			promise:cancel()

			expect(internal:getStatus()).to.equal(Promise.Status.Cancelled)
		end)
	end)

	describe("Promise.all", function()
		it("should error if given something other than a table", function()
			expect(function()
				Promise.all(1)
			end).to.throw()
		end)

		it("should resolve instantly with an empty table if given no promises", function()
			local promise = Promise.all({})
			local success, value = promise:_unwrap()

			expect(success).to.equal(true)
			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(value).to.be.a("table")
			expect(next(value)).to.equal(nil)
		end)

		it("should error if given non-promise values", function()
			expect(function()
				Promise.all({ {}, {}, {} })
			end).to.throw()
		end)

		it("should wait for all promises to be resolved and return their values", function()
			local resolveFunctions = {}

			local testValuesLength, testValues = pack(1, "A string", nil, false)

			local promises = {}

			for i = 1, testValuesLength do
				promises[i] = Promise.new(function(resolve)
					resolveFunctions[i] = { resolve, testValues[i] }
				end)
			end

			local combinedPromise = Promise.all(promises)

			for _, resolve in ipairs(resolveFunctions) do
				expect(combinedPromise:getStatus()).to.equal(Promise.Status.Started)
				resolve[1](resolve[2])
			end

			local resultLength, result = pack(combinedPromise:_unwrap())
			local success, resolved = unpack(result, 1, resultLength)

			expect(resultLength).to.equal(2)
			expect(success).to.equal(true)
			expect(resolved).to.be.a("table")
			expect(#resolved).to.equal(#promises)

			for i = 1, testValuesLength do
				expect(resolved[i]).to.equal(testValues[i])
			end
		end)

		it("should reject if any individual promise rejected", function()
			local rejectA
			local resolveB

			local a = Promise.new(function(_, reject)
				rejectA = reject
			end)

			local b = Promise.new(function(resolve)
				resolveB = resolve
			end)

			local combinedPromise = Promise.all({ a, b })

			expect(combinedPromise:getStatus()).to.equal(Promise.Status.Started)

			rejectA("baz", "qux")
			resolveB("foo", "bar")

			local resultLength, result = pack(combinedPromise:_unwrap())
			local success, first, second = unpack(result, 1, resultLength)

			expect(resultLength).to.equal(3)
			expect(success).to.equal(false)
			expect(first).to.equal("baz")
			expect(second).to.equal("qux")
			expect(b:getStatus()).to.equal(Promise.Status.Cancelled)
		end)

		it("should not resolve if resolved after rejecting", function()
			local rejectA
			local resolveB

			local a = Promise.new(function(_, reject)
				rejectA = reject
			end)

			local b = Promise.new(function(resolve)
				resolveB = resolve
			end)

			local combinedPromise = Promise.all({ a, b })

			expect(combinedPromise:getStatus()).to.equal(Promise.Status.Started)

			rejectA("baz", "qux")
			resolveB("foo", "bar")

			local resultLength, result = pack(combinedPromise:_unwrap())
			local success, first, second = unpack(result, 1, resultLength)

			expect(resultLength).to.equal(3)
			expect(success).to.equal(false)
			expect(first).to.equal("baz")
			expect(second).to.equal("qux")
		end)

		it("should only reject once", function()
			local rejectA
			local rejectB

			local a = Promise.new(function(_, reject)
				rejectA = reject
			end)

			local b = Promise.new(function(_, reject)
				rejectB = reject
			end)

			local combinedPromise = Promise.all({ a, b })

			expect(combinedPromise:getStatus()).to.equal(Promise.Status.Started)

			rejectA("foo", "bar")

			expect(combinedPromise:getStatus()).to.equal(Promise.Status.Rejected)

			rejectB("baz", "qux")

			local resultLength, result = pack(combinedPromise:_unwrap())
			local success, first, second = unpack(result, 1, resultLength)

			expect(resultLength).to.equal(3)
			expect(success).to.equal(false)
			expect(first).to.equal("foo")
			expect(second).to.equal("bar")
		end)

		it("should error if a non-array table is passed in", function()
			local ok, err = pcall(function()
				Promise.all(Promise.new(function() end))
			end)

			expect(ok).to.be.ok()
			expect(err:find("Non%-promise")).to.be.ok()
		end)

		it("should cancel pending promises if one rejects", function()
			local p = Promise.new(function() end)
			expect(Promise.all({
				Promise.resolve(),
				Promise.reject(),
				p,
			}):getStatus()).to.equal(Promise.Status.Rejected)
			expect(p:getStatus()).to.equal(Promise.Status.Cancelled)
		end)

		it("should cancel promises if it is cancelled", function()
			local p = Promise.new(function() end)
			p:andThen(function() end)

			local promises = {
				Promise.new(function() end),
				Promise.new(function() end),
				p,
			}

			Promise.all(promises):cancel()

			expect(promises[1]:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(promises[2]:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(promises[3]:getStatus()).to.equal(Promise.Status.Started)
		end)
	end)

	describe("Promise.fold", function()
		it("should return the initial value in a promise when the list is empty", function()
			local initialValue = {}
			local result = Promise.fold({}, function()
				error("should not be called")
			end, initialValue)

			expect(Promise.is(result)).to.equal(true)
			expect(result:getStatus()).to.equal(Promise.Status.Resolved)
			expect(result:expect()).to.equal(initialValue)
		end)

		it("should accept promises in the list", function()
			local resolve

			local sum = Promise.fold({ Promise.new(function(r)
				resolve = r
			end), 2, 3 }, function(sum, element)
				return sum + element
			end, 0)

			resolve(1)

			expect(Promise.is(sum)).to.equal(true)
			expect(sum:getStatus()).to.equal(Promise.Status.Resolved)
			expect(sum:expect()).to.equal(6)
		end)

		it("should always return a promise even if the list or reducer don't use them", function()
			local sum = Promise.fold({ 1, 2, 3 }, function(sum, element, index)
				if index == 2 then
					return Promise.delay(1):andThenReturn(sum + element)
				else
					return sum + element
				end
			end, 0)
			expect(Promise.is(sum)).to.equal(true)
			expect(sum:getStatus()).to.equal(Promise.Status.Started)
			advanceTime(2)
			expect(sum:getStatus()).to.equal(Promise.Status.Resolved)
			expect(sum:expect()).to.equal(6)
		end)

		it("should return the first rejected promise", function()
			local errorMessage = "foo"
			local sum = Promise.fold({ 1, 2, 3 }, function(sum, element, index)
				if index == 2 then
					return Promise.reject(errorMessage)
				else
					return sum + element
				end
			end, 0)
			expect(Promise.is(sum)).to.equal(true)
			local status, rejection = sum:awaitStatus()
			expect(status).to.equal(Promise.Status.Rejected)
			expect(rejection).to.equal(errorMessage)
		end)

		it("should return the first canceled promise", function()
			local secondPromise
			local sum = Promise.fold({ 1, 2, 3 }, function(sum, element, index)
				if index == 1 then
					return sum + element
				elseif index == 2 then
					secondPromise = Promise.delay(1):andThenReturn(sum + element)
					return secondPromise
				else
					error("this should not run if the promise is cancelled")
				end
			end, 0)
			expect(Promise.is(sum)).to.equal(true)
			expect(sum:getStatus()).to.equal(Promise.Status.Started)
			secondPromise:cancel()
			expect(sum:getStatus()).to.equal(Promise.Status.Cancelled)
		end)
	end)

	describe("Promise.race", function()
		it("should resolve with the first settled value", function()
			local promise = Promise.race({
				Promise.resolve(1),
				Promise.resolve(2),
			}):andThen(function(value)
				expect(value).to.equal(1)
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
		end)

		it("should cancel other promises", function()
			local promise = Promise.new(function() end)
			promise:andThen(function() end)
			local promises = {
				promise,
				Promise.new(function() end),
				Promise.new(function(resolve)
					resolve(2)
				end),
			}

			local promise = Promise.race(promises)

			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(promise._values[1]).to.equal(2)
			expect(promises[1]:getStatus()).to.equal(Promise.Status.Started)
			expect(promises[2]:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(promises[3]:getStatus()).to.equal(Promise.Status.Resolved)

			local p = Promise.new(function() end)
			expect(Promise.race({
				Promise.reject(),
				Promise.resolve(),
				p,
			}):getStatus()).to.equal(Promise.Status.Rejected)
			expect(p:getStatus()).to.equal(Promise.Status.Cancelled)
		end)

		it("should error if a non-array table is passed in", function()
			local ok, err = pcall(function()
				Promise.race(Promise.new(function() end))
			end)

			expect(ok).to.be.ok()
			expect(err:find("Non%-promise")).to.be.ok()
		end)

		it("should cancel promises if it is cancelled", function()
			local p = Promise.new(function() end)
			p:andThen(function() end)

			local promises = {
				Promise.new(function() end),
				Promise.new(function() end),
				p,
			}

			Promise.race(promises):cancel()

			expect(promises[1]:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(promises[2]:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(promises[3]:getStatus()).to.equal(Promise.Status.Started)
		end)
	end)

	describe("Promise.promisify", function()
		it("should wrap functions", function()
			local function test(n)
				return n + 1
			end

			local promisified = Promise.promisify(test)
			local promise = promisified(1)
			local success, result = promise:_unwrap()

			expect(success).to.equal(true)
			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(result).to.equal(2)
		end)

		it("should catch errors after a yield", function()
			local bindable = Instance.new("BindableEvent")
			local test = Promise.promisify(function()
				bindable.Event:Wait()
				error("errortext")
			end)

			local promise = test()

			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			bindable:Fire()
			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(tostring(promise._values[1]):find("errortext")).to.be.ok()
		end)
	end)

	describe("Promise.tap", function()
		it("should thread through values", function()
			local first, second

			Promise.resolve(1)
				:andThen(function(v)
					return v + 1
				end)
				:tap(function(v)
					first = v
					return v + 1
				end)
				:andThen(function(v)
					second = v
				end)

			expect(first).to.equal(2)
			expect(second).to.equal(2)
		end)

		it("should chain onto promises", function()
			local resolveInner, finalValue

			local promise = Promise.resolve(1)
				:tap(function()
					return Promise.new(function(resolve)
						resolveInner = resolve
					end)
				end)
				:andThen(function(v)
					finalValue = v
				end)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			expect(finalValue).to.never.be.ok()

			resolveInner(1)

			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(finalValue).to.equal(1)
		end)
	end)

	describe("Promise.try", function()
		it("should catch synchronous errors", function()
			local errorText
			Promise.try(function()
				error("errortext")
			end):catch(function(e)
				errorText = tostring(e)
			end)

			expect(errorText:find("errortext")).to.be.ok()
		end)

		it("should reject with error objects", function()
			local object = {}
			local success, value = Promise.try(function()
				error(object)
			end):_unwrap()

			expect(success).to.equal(false)
			expect(value).to.equal(object)
		end)

		it("should catch asynchronous errors", function()
			local bindable = Instance.new("BindableEvent")
			local promise = Promise.try(function()
				bindable.Event:Wait()
				error("errortext")
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			bindable:Fire()
			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(tostring(promise._values[1]):find("errortext")).to.be.ok()
		end)
	end)

	describe("Promise:andThenReturn", function()
		it("should return the given values", function()
			local value1, value2

			Promise.resolve():andThenReturn(1, 2):andThen(function(one, two)
				value1 = one
				value2 = two
			end)

			expect(value1).to.equal(1)
			expect(value2).to.equal(2)
		end)
	end)

	describe("Promise:andThenCall", function()
		it("should call the given function with arguments", function()
			local value1, value2
			Promise.resolve():andThenCall(function(a, b)
				value1 = a
				value2 = b
			end, 3, 4)

			expect(value1).to.equal(3)
			expect(value2).to.equal(4)
		end)
	end)

	describe("Promise.some", function()
		it("should resolve once the goal is reached", function()
			local p = Promise.some({
				Promise.resolve(1),
				Promise.reject(),
				Promise.resolve(2),
			}, 2)
			expect(p:getStatus()).to.equal(Promise.Status.Resolved)
			expect(p._values[1][1]).to.equal(1)
			expect(p._values[1][2]).to.equal(2)
		end)

		it("should error if the goal can't be reached", function()
			expect(Promise.some({
				Promise.resolve(),
				Promise.reject(),
			}, 2):getStatus()).to.equal(Promise.Status.Rejected)

			local reject
			local p = Promise.some({
				Promise.resolve(),
				Promise.new(function(_, r)
					reject = r
				end),
			}, 2)

			expect(p:getStatus()).to.equal(Promise.Status.Started)
			reject("foo")
			expect(p:getStatus()).to.equal(Promise.Status.Rejected)
			expect(p._values[1]).to.equal("foo")
		end)

		it("should cancel pending Promises once the goal is reached", function()
			local resolve
			local pending1 = Promise.new(function() end)
			local pending2 = Promise.new(function(r)
				resolve = r
			end)

			local some = Promise.some({
				pending1,
				pending2,
				Promise.resolve(),
			}, 2)

			expect(some:getStatus()).to.equal(Promise.Status.Started)
			expect(pending1:getStatus()).to.equal(Promise.Status.Started)
			expect(pending2:getStatus()).to.equal(Promise.Status.Started)

			resolve()

			expect(some:getStatus()).to.equal(Promise.Status.Resolved)
			expect(pending1:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(pending2:getStatus()).to.equal(Promise.Status.Resolved)
		end)

		it("should error if passed a non-number", function()
			expect(function()
				Promise.some({}, "non-number")
			end).to.throw()
		end)

		it("should return an empty array if amount is 0", function()
			local p = Promise.some({
				Promise.resolve(2),
			}, 0)

			expect(p:getStatus()).to.equal(Promise.Status.Resolved)
			expect(#p._values[1]).to.equal(0)
		end)

		it("should not return extra values", function()
			local p = Promise.some({
				Promise.resolve(1),
				Promise.resolve(2),
				Promise.resolve(3),
				Promise.resolve(4),
			}, 2)

			expect(p:getStatus()).to.equal(Promise.Status.Resolved)
			expect(#p._values[1]).to.equal(2)
			expect(p._values[1][1]).to.equal(1)
			expect(p._values[1][2]).to.equal(2)
		end)

		it("should cancel promises if it is cancelled", function()
			local p = Promise.new(function() end)
			p:andThen(function() end)

			local promises = {
				Promise.new(function() end),
				Promise.new(function() end),
				p,
			}

			Promise.some(promises, 3):cancel()

			expect(promises[1]:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(promises[2]:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(promises[3]:getStatus()).to.equal(Promise.Status.Started)
		end)

		describe("Promise.any", function()
			it("should return the value directly", function()
				local p = Promise.any({
					Promise.reject(),
					Promise.reject(),
					Promise.resolve(1),
				})

				expect(p:getStatus()).to.equal(Promise.Status.Resolved)
				expect(p._values[1]).to.equal(1)
			end)

			it("should error if all are rejected", function()
				expect(Promise.any({
					Promise.reject(),
					Promise.reject(),
					Promise.reject(),
				}):getStatus()).to.equal(Promise.Status.Rejected)
			end)
		end)
	end)

	describe("Promise.allSettled", function()
		it("should resolve with an array of PromiseStatuses", function()
			local reject
			local p = Promise.allSettled({
				Promise.resolve(),
				Promise.reject(),
				Promise.resolve(),
				Promise.new(function(_, r)
					reject = r
				end),
			})

			expect(p:getStatus()).to.equal(Promise.Status.Started)
			reject()
			expect(p:getStatus()).to.equal(Promise.Status.Resolved)
			expect(p._values[1][1]).to.equal(Promise.Status.Resolved)
			expect(p._values[1][2]).to.equal(Promise.Status.Rejected)
			expect(p._values[1][3]).to.equal(Promise.Status.Resolved)
			expect(p._values[1][4]).to.equal(Promise.Status.Rejected)
		end)

		it("should cancel promises if it is cancelled", function()
			local p = Promise.new(function() end)
			p:andThen(function() end)

			local promises = {
				Promise.new(function() end),
				Promise.new(function() end),
				p,
			}

			Promise.allSettled(promises):cancel()

			expect(promises[1]:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(promises[2]:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(promises[3]:getStatus()).to.equal(Promise.Status.Started)
		end)
	end)

	describe("Promise:await", function()
		it("should return the correct values", function()
			local promise = Promise.resolve(5, 6, nil, 7)

			local a, b, c, d, e = promise:await()

			expect(a).to.equal(true)
			expect(b).to.equal(5)
			expect(c).to.equal(6)
			expect(d).to.equal(nil)
			expect(e).to.equal(7)
		end)

		it("should work if yielding is needed", function()
			local ran = false
			task.spawn(function()
				local _, actualTime = Promise.delay(1):await()
				expect(type(actualTime)).to.equal("number")
				ran = true
			end)

			advanceTime(2)
			expect(ran).to.equal(true)
		end)
	end)

	describe("Promise:expect", function()
		it("should throw the correct values", function()
			local rejectionValue = {}
			local promise = Promise.reject(rejectionValue)

			local success, value = pcall(function()
				promise:expect()
			end)

			expect(success).to.equal(false)
			expect(value).to.equal(rejectionValue)
		end)
	end)

	describe("Promise:now", function()
		it("should resolve if the Promise is resolved", function()
			local success, value = Promise.resolve("foo"):now():_unwrap()

			expect(success).to.equal(true)
			expect(value).to.equal("foo")
		end)

		it("should reject if the Promise is not resolved", function()
			local success, value = Promise.new(function() end):now():_unwrap()

			expect(success).to.equal(false)
			expect(Promise.Error.isKind(value, "NotResolvedInTime")).to.equal(true)
		end)

		it("should reject with a custom rejection value", function()
			local success, value = Promise.new(function() end):now("foo"):_unwrap()

			expect(success).to.equal(false)
			expect(value).to.equal("foo")
		end)
	end)

	describe("Promise.each", function()
		it("should iterate", function()
			local ok, result = Promise.each({
				"foo",
				"bar",
				"baz",
				"qux",
			}, function(...)
				return { ... }
			end):_unwrap()

			expect(ok).to.equal(true)
			expect(result[1][1]).to.equal("foo")
			expect(result[1][2]).to.equal(1)
			expect(result[2][1]).to.equal("bar")
			expect(result[2][2]).to.equal(2)
			expect(result[3][1]).to.equal("baz")
			expect(result[3][2]).to.equal(3)
			expect(result[4][1]).to.equal("qux")
			expect(result[4][2]).to.equal(4)
		end)

		it("should iterate serially", function()
			local resolves = {}
			local callCounts = {}

			local promise = Promise.each({
				"foo",
				"bar",
				"baz",
			}, function(value, index)
				callCounts[index] = (callCounts[index] or 0) + 1

				return Promise.new(function(resolve)
					table.insert(resolves, function()
						resolve(value:upper())
					end)
				end)
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			expect(#resolves).to.equal(1)
			expect(callCounts[1]).to.equal(1)
			expect(callCounts[2]).to.never.be.ok()

			table.remove(resolves, 1)()

			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			expect(#resolves).to.equal(1)
			expect(callCounts[1]).to.equal(1)
			expect(callCounts[2]).to.equal(1)
			expect(callCounts[3]).to.never.be.ok()

			table.remove(resolves, 1)()

			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			expect(callCounts[1]).to.equal(1)
			expect(callCounts[2]).to.equal(1)
			expect(callCounts[3]).to.equal(1)

			table.remove(resolves, 1)()

			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(type(promise._values[1])).to.equal("table")
			expect(type(promise._values[2])).to.equal("nil")

			local result = promise._values[1]

			expect(result[1]).to.equal("FOO")
			expect(result[2]).to.equal("BAR")
			expect(result[3]).to.equal("BAZ")
		end)

		it("should reject with the value if the predicate promise rejects", function()
			local promise = Promise.each({ 1, 2, 3 }, function()
				return Promise.reject("foobar")
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(promise._values[1]).to.equal("foobar")
		end)

		it("should allow Promises to be in the list and wait when it gets to them", function()
			local innerResolve
			local innerPromise = Promise.new(function(resolve)
				innerResolve = resolve
			end)

			local promise = Promise.each({
				innerPromise,
			}, function(value)
				return value * 2
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)

			innerResolve(2)

			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(promise._values[1][1]).to.equal(4)
		end)

		it("should reject with the value if a Promise from the list rejects", function()
			local called = false
			local promise = Promise.each({ 1, 2, Promise.reject("foobar") }, function(value)
				called = true
				return "never"
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(promise._values[1]).to.equal("foobar")
			expect(called).to.equal(false)
		end)

		it("should reject immediately if there's a cancelled Promise in the list initially", function()
			local cancelled = Promise.new(function() end)
			cancelled:cancel()

			local called = false
			local promise = Promise.each({ 1, 2, cancelled }, function()
				called = true
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(called).to.equal(false)
			expect(promise._values[1].kind).to.equal(Promise.Error.Kind.AlreadyCancelled)
		end)

		it("should stop iteration if Promise.each is cancelled", function()
			local callCounts = {}

			local promise = Promise.each({
				"foo",
				"bar",
				"baz",
			}, function(value, index)
				callCounts[index] = (callCounts[index] or 0) + 1

				return Promise.new(function() end)
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)
			expect(callCounts[1]).to.equal(1)
			expect(callCounts[2]).to.never.be.ok()

			promise:cancel()

			expect(promise:getStatus()).to.equal(Promise.Status.Cancelled)
			expect(callCounts[1]).to.equal(1)
			expect(callCounts[2]).to.never.be.ok()
		end)

		it("should cancel the Promise returned from the predicate if Promise.each is cancelled", function()
			local innerPromise

			local promise = Promise.each({
				"foo",
				"bar",
				"baz",
			}, function(value, index)
				innerPromise = Promise.new(function() end)
				return innerPromise
			end)

			promise:cancel()

			expect(innerPromise:getStatus()).to.equal(Promise.Status.Cancelled)
		end)

		it("should cancel Promises in the list if Promise.each is cancelled", function()
			local innerPromise = Promise.new(function() end)

			local promise = Promise.each({ innerPromise }, function() end)

			promise:cancel()

			expect(innerPromise:getStatus()).to.equal(Promise.Status.Cancelled)
		end)
	end)

	describe("Promise.retry", function()
		it("should retry N times", function()
			local counter = 0

			local promise = Promise.retry(function(parameter)
				expect(parameter).to.equal("foo")

				counter = counter + 1

				if counter == 5 then
					return Promise.resolve("ok")
				end

				return Promise.reject("fail")
			end, 5, "foo")

			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(promise._values[1]).to.equal("ok")
		end)

		it("should reject if threshold is exceeded", function()
			local promise = Promise.retry(function()
				return Promise.reject("fail")
			end, 5)

			expect(promise:getStatus()).to.equal(Promise.Status.Rejected)
			expect(promise._values[1]).to.equal("fail")
		end)
	end)

	describe("Promise.retryWithDelay", function()
		it("should retry after a delay", function()
			local counter = 0

			local promise = Promise.retryWithDelay(function(parameter)
				expect(parameter).to.equal("foo")

				counter = counter + 1

				if counter == 3 then
					return Promise.resolve("ok")
				end

				return Promise.reject("fail")
			end, 3, 10, "foo")

			expect(counter).to.equal(1)

			advanceTime(11)

			expect(counter).to.equal(2)

			advanceTime(11)

			expect(counter).to.equal(3)

			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(promise._values[1]).to.equal("ok")
		end)
	end)

	describe("Promise.fromEvent", function()
		it("should convert a Promise into an event", function()
			local event = Instance.new("BindableEvent")

			local promise = Promise.fromEvent(event.Event)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)

			event:Fire("foo")

			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(promise._values[1]).to.equal("foo")
		end)

		it("should convert a Promise into an event with the predicate", function()
			local event = Instance.new("BindableEvent")

			local promise = Promise.fromEvent(event.Event, function(param)
				return param == "foo"
			end)

			expect(promise:getStatus()).to.equal(Promise.Status.Started)

			event:Fire("bar")

			expect(promise:getStatus()).to.equal(Promise.Status.Started)

			event:Fire("foo")

			expect(promise:getStatus()).to.equal(Promise.Status.Resolved)
			expect(promise._values[1]).to.equal("foo")
		end)
	end)

	describe("Promise.is", function()
		it("should work with current version", function()
			local promise = Promise.resolve(1)

			expect(Promise.is(promise)).to.equal(true)
		end)

		it("should work with any object with an andThen", function()
			local obj = {
				andThen = function()
					return 1
				end,
			}

			expect(Promise.is(obj)).to.equal(true)
		end)

		it("should work with older promises", function()
			local OldPromise = {}
			OldPromise.prototype = {}
			OldPromise.__index = OldPromise.prototype

			function OldPromise.prototype:andThen() end

			local oldPromise = setmetatable({}, OldPromise)

			expect(Promise.is(oldPromise)).to.equal(true)
		end)
	end)
end
