Best JavaScript code snippet using storybook-root
test.js
Source:test.js
...64 return Promise.resolve(response.entity);65 });66}6768function parseCall(auth, apiName, payload) {6970 var headers = {71 "Content-Type": "application/json",72 "X-Parse-Application-Id": appId73 };7475 if (typeof(auth) == 'string') {76 var token = tokens[auth];77 if (typeof(token) != "string" || token === "") {78 return Promise.reject(new Error("Token missing for " + auth));79 }80 headers["X-Parse-Session-Token"] = token;81 } else if (auth && typeof(auth) == 'object') {82 if (auth.useMasterKey) {83 headers["X-Parse-Master-Key"] = masterKey;84 }85 }8687 if (apiName.indexOf("/") == -1) apiName = "functions/" + apiName;8889 return client({90 path: urlParse + apiName,91 headers: headers,92 entity: payload93 }).then(function(response) {94 response.should.have.property("entity");95 return Promise.resolve(response.entity);96 });97}9899function parseError(message) {100 return (function(entity) {101 entityError(entity, message);102 });103}104105106function entityResult(entity, message) {107 if (typeof(entity.error) == 'string') should.not.exist(entity.error);108 if (entity.error) should.not.exist(entity.error.message);109 if (entity.code) should.not.exist(entity.message);110 entity.should.have.property("result");111 if (message) {112 entity.result.code.should.equal(message.id);113 }114 return entity.result;115}116117function entityError(entity, message) {118 if (!message.id) throw new Error("Invalid message provided");119120 // Cloud Code Error Code121 122 if (entity.result) {123 var unexpected = messageById[entity.result.code];124 should.not.exist(unexpected);125 }126127 entity.should.have.property("code");128 entity.code.should.equal(141);129130 entity.should.have.property("error");131 132 var error = entity.error;133 error.should.be.an("object");134135 error.should.have.property("message");136 error.message.should.be.a("string");137 138 error.should.have.property("code");139 error.code.should.be.a("number");140141 var expected = messageById[message.id];142 expected = expected ? expected + " (" + message.id + ")" : message.id;143144 var actual = messageById[error.code];145 if (!actual && error.code >= 1999 && error.code < 3000) {146 actual = "ParseError";147 actual = actual + " (2/" + (error.code - 2000) + ")";148 } else {149 actual = actual ? actual + " (" + error.code + ")" : error.code;150 }151152 var msg = "Expected " + actual + " to equal " + expected + "\n" + util.inspect(error);153 error.code.should.equal(message.id, msg);154155 error.should.not.have.property("error");156}157158function entityGameId(entity) {159 var result = entityResult(entity);160 result.should.have.property("game");161 var game = result.game;162 game.should.have.property("objectId");163 game.objectId.should.be.a("string");164 return game.objectId;165}166167function getUserSessions() {168 var sessionFile = __dirname + "/sessions.json";169 var mainPromise = new Promise();170 fs.readFile(sessionFile, "utf8", function(err, data) {171 var pending = [];172 if (err && err.code == "ENOENT") {173 console.info("Sessions file missing, rebuilding: " + sessionFile);174 pending = logins;175 } else {176 tokens = JSON.parse(data);177 logins.forEach(function(login) {178 if (!tokens[login.name]) pending.push(login);179 }, this);180 }181 182 var promises = [];183 pending.forEach(function(login) {184 promises.push(requestLogin(login.user, login.pass));185 }, this);186187 if (promises.length === 0) {188 return mainPromise.resolve();189 } else {190 return Promise.when(promises).then(191 function(results) {192 results.forEach(function(loginResult) {193 var user = loginResult.username;194 var name = logins.find(function(login) {195 return login.user == user;196 }).name;197 tokens[name] = loginResult.sessionToken;198 console.log("Updated session token for " + user);199 }, this);200201 fs.writeFile(sessionFile, JSON.stringify(tokens), function(err) {202 if (err) {203 mainPromise.reject(new Error(204 "Unable to update sessions file: " + err205 ));206 } else {207 console.log("Sessions file updated");208 mainPromise.resolve();209 }210 });211 },212 function(error) {213 console.error(error);214 mainPromise.reject(new Error("Unable to login all users"));215 }216 );217 }218 219 });220221 return mainPromise;222}223224function joinGameCheck(entity) {225 entityResult(entity, constants.t.GAME_JOINED)226 .should.have.deep.property("player.objectId");227}228229function resultShouldError(message) {230 if (!message.id) {231 resultShouldError({ id: -1 })(message);232 }233 return (function(entity) {234 entityError(entity, message);235 });236}237238function joinGame(name, game, desc, playerFunc) {239 if (!desc) desc = 'has ' + name + ' join game and get player id';240 it(desc, function() {241 return parseCall(name, "joinGame", {242 gameId: game.id243 }).then(244 function(entity) {245 if (playerFunc) playerFunc(entity);246 else joinGameCheck(entity);247 }248 );249 });250}251252function leaveGame(name, game, desc, playerFunc) {253 if (!desc) desc = 'has ' + name + ' leave game';254 it(desc, function() {255 return parseCall(name, "leaveGame", {256 gameId: game.id257 }).then(258 function(entity) {259 if (playerFunc) playerFunc(entity);260 else entityResult(entity, constants.t.GAME_LEFT);261 }262 );263 });264}265266function purgeGames() {267 return parseCall({ useMasterKey: true }, "purgeGamesABCD",268 {}269 ).then(270 function(result) {271 result.should.have.property("result");272 should.equal(result.result.purged, true);273 }274 );275}276277function purgeRandom() {278 it('should remove random games first', function() {279 return parseCall({ useMasterKey: true }, "purgeRandomGames",280 {}281 ).then(282 function(result) {283 result.should.have.property("result");284 should.equal(result.result.purged, true);285 }286 );287 });288}289290function internalStartGame(name, game, desc, customFunc, delay) {291 var timeBuffer = 1;292 if (!desc) desc = 'has ' + name + ' start the game';293 it(desc, function() {294 295 var promise = new Promise();296297 if (delay === 0) {298 promise.resolve();299 } else {300 var relativeDelay = delay - (game.startTime > 0 ? (Date.now() - game.startTime) : 0);301 if (relativeDelay <= 0) {302 promise.resolve();303 } else {304 this.timeout(2000 + relativeDelay);305306 setTimeout(function() {307 promise.resolve();308 }, relativeDelay);309 }310 }311312 return promise.then(function() {313 return parseCall(name, "startGame", {314 gameId: game.id315 });316 }).then(317 function(entity) {318 if (customFunc) customFunc(entity);319 else {320 var result = entityResult(entity, constants.t.GAME_STARTED);321 result.should.have.deep.property("player.objectId");322 result.game.state.should.equal(GameState.Running);323 }324 }325 );326 });327}328329function waitAndStartGame(name, game, desc, customFunc) {330 if (testTimeouts) internalStartGame(name, game, desc, customFunc, constants.START_GAME_MANUAL_TIMEOUT*1000);331}332333function startGame(name, game, desc, customFunc) {334 internalStartGame(name, game, desc, customFunc, 0);335}336337function listGames(name, gamesObj, desc, testFunc) {338 it(desc, function() {339 var req = {};340 if (gamesObj) {341 var games = null;342 if (Array.isArray(gamesObj)) {343 games = gamesObj;344 } else {345 games = gamesObj.games;346 req.typeId = gamesObj.typeId;347 }348 if (games) req.gameIds = games.map(function(game) { return game.id; });349 }350 return parseCall(name, "listGames", req).then(351 function(entity) {352 var result = entityResult(entity, constants.t.GAME_LIST);353 result.should.have.property("games");354 result.games.should.be.an("array");355 testFunc(result.games);356 }357 );358 });359}360361function getGame(name, game, desc, testFunc) {362 if (!desc) desc = 'returns the right game status to ' + name;363 listGames(name, { games: [game], typeId: game.typeId }, desc, function(games) {364 games.should.have.length(1);365 testFunc(games[0]);366 });367}368369function makeTurn(name, game, type, turnNumber) {370 var msg;371 switch (type) {372 case "invalid": msg = "get invalid state for"; break;373 default: msg = type;374 }375 it('should ' + msg + ' game turn by ' + name, function() {376 return parseCall(name, "gameTurn", {377 gameId: game.id,378 save: "turn " + turnNumber,379 final: type == "finish"380 }).then(381 function(entity) {382 switch (type) {383 case "allow":384 entityResult(entity, constants.t.TURN_SAVED);385 break;386 387 case "invalid":388 entityError(entity, constants.t.GAME_INVALID_STATE);389 break;390391 case "deny":392 entityError(entity, constants.t.TURN_NOT_IT);393 break;394395 case "finish":396 var result = entityResult(entity, constants.t.TURN_SAVED);397 result.should.have.property("ended");398 result.ended.should.equal(true);399 break;400401 default:402 should.fail(entity, "supported type", "Invalid turn type");403 }404 }405 );406 });407}408409function getJob(id) {410 var promise = new Promise();411 kue.Job.get(id, function(err, job) {412 if (err) {413 promise.reject(new Error(err));414 return;415 }416 promise.resolve(job);417 });418 return promise;419}420421function checkDeletedJob(id) {422 var promise = new Promise();423 getJob(id).then(424 function(job) {425 promise.reject(new Error(426 "Job was found, but it should've been deleted: " + job.id427 ));428 },429 function(err) {430 promise.resolve();431 }432 );433 return promise;434}435436437describe('public', function() {438 describe('name check', function() {439440 function checkName(desc, name, err) {441 it(desc, function() {442 return parseCall(null, "checkNameFree", {443 displayName: name444 }).then(445 function(entity) {446 var result = entityResult(entity);447 result.available.should.equal(!err);448 if (err) {449 result.should.have.property("reason");450 result.reason.code.should.equal(err.id);451 }452 }453 );454 });455 }456457 checkName("denies existing name", "Ally", constants.t.DISPLAY_NAME_TAKEN);458 checkName("approves a free name", "47421dabef3b", null);459 checkName("denies too short name", "a", constants.t.INVALID_PARAMETER);460 checkName("denies too long name", "ThisNameIsWayTooLongAndDefinitelyGoesOverTheLimit", constants.t.INVALID_PARAMETER);461 checkName("denies an obscene name", "shitosaur", constants.t.DISPLAY_NAME_BLACKLISTED);462 463 it("should error on missing parameter", function() {464 return parseCall(null, "checkNameFree", {}).then(465 parseError(constants.t.INVALID_PARAMETER)466 );467 });468469 it("should error on empty name", function() {470 return parseCall(null, "checkNameFree", {471 displayName: ""472 }).then(473 parseError(constants.t.INVALID_PARAMETER)474 );475 });476477 });478});479480481describe('game flow', function() {482 before(getUserSessions);483484 describe('invite', function() {485486 function checkSlots(game, expectedFill) {487 listGames("Alice", [game],488 "should return these slots as filled: " + expectedFill,489 function(games) {490 games.should.have.length(1);491 game.id.should.equal(games[0].objectId);492493 var slots = games[0].config.slots;494 var filled = slots.map(function(slot) {495 return slot.filled;496 })497498 filled.should.deep.equal(expectedFill);499500 }501 );502 }503504 describe('four player game', function() {505 506 var game = {};507508 it('creates a game and gets the game id with Alice', function() {509 return parseCall("Alice", "createGame", {510 "slots": [511 { type: "creator" },512 { type: "open" },513 { type: "invite", displayName: "Bobzor" },514 { type: "invite", displayName: "Carry" },515 ],516 "fameCards": {},517 "turnMaxSec": 60518 }).then(519 function(entity) {520 game.id = entityGameId(entity);521 var result = entityResult(entity, constants.t.GAME_CREATED);522 result.game.state.should.equal(GameState.Lobby);523524 var slots = result.game.config.slots;525 slots.should.have.length(4);526 slots[3].type.should.equal("invite");527528 }529 );530 });531 532 checkSlots(game, [true, false, false, false])533534 joinGame("Bob", game);535 checkSlots(game, [true, false, true, false])536 listGames("Alice", [game],537 "should keep the same slot type",538 function(games) {539 games.should.have.length(1);540 game.id.should.equal(games[0].objectId);541542 var slots = games[0].config.slots;543 slots.should.have.length(4);544 slots[3].type.should.equal("invite");545 }546 );547548 it('declines invite with Carol', function() {549 return parseCall("Carol", "declineInvite", {550 "gameId": game.id551 }).then(552 function(entity) {553 entityResult(entity, constants.t.GAME_INVITE_DECLINED);554 }555 );556 });557 checkSlots(game, [true, false, true, false])558559 listGames("Alice", [game],560 "should have the slot type changed to open",561 function(games) {562 games.should.have.length(1);563 game.id.should.equal(games[0].objectId);564565 var slots = games[0].config.slots;566 slots.should.have.length(4);567 slots[3].type.should.equal("open");568 }569 );570 })571572 describe('two player game', function() {573 574 var game = {};575576 purgeRandom();577578 it('creates a game and gets the game id with Alice', function() {579 return parseCall("Alice", "createGame", {580 "slots": [581 { type: "creator" },582 { type: "invite", displayName: "Bobzor" },583 ],584 "fameCards": {},585 "turnMaxSec": 60586 }).then(587 function(entity) {588 game.id = entityGameId(entity);589 var result = entityResult(entity, constants.t.GAME_CREATED);590 result.game.state.should.equal(GameState.Lobby);591592 var slots = result.game.config.slots;593 slots.should.have.length(2);594 slots[1].type.should.equal("invite");595 }596 );597 });598 599 it('finds no games with Bob', function() {600 return parseCall("Bob", "findGames", {601 }).then(602 function(entity) {603 var result = entityResult(entity, constants.t.GAME_LIST);604 result.should.have.property("games");605 result.games.should.have.length(0);606 }607 );608 });609 610 it('finds no games with Carol', function() {611 return parseCall("Carol", "findGames", {612 }).then(613 function(entity) {614 var result = entityResult(entity, constants.t.GAME_LIST);615 result.should.have.property("games");616 result.games.should.have.length(0);617 }618 );619 });620621 it('declines invite with Bob', function() {622 return parseCall("Bob", "declineInvite", {623 "gameId": game.id624 }).then(625 function(entity) {626 entityResult(entity, constants.t.GAME_INVITE_DECLINED);627 }628 );629 });630 checkSlots(game, [true, false])631632 it('should find a game with Bob after declining invite', function() {633 return parseCall("Bob", "findGames", {634 }).then(635 function(entity) {636 var result = entityResult(entity, constants.t.GAME_LIST);637 result.should.have.property("games");638 result.games.should.have.length(1);639 }640 );641 });642 643 it('should find a game with Carol after declining invite', function() {644 return parseCall("Carol", "findGames", {645 }).then(646 function(entity) {647 var result = entityResult(entity, constants.t.GAME_LIST);648 result.should.have.property("games");649 result.games.should.have.length(1);650 }651 );652 });653 654 })655656 describe("list", function() {657658 var gameByName = {};659660 it('creates an Alice game inviting Bob and Carol', function() {661 return parseCall("Alice", "createGame", {662 "slots": [663 { type: "creator" },664 { type: "open" },665 { type: "invite", displayName: "Bobzor" },666 { type: "invite", displayName: "Carry" },667 ],668 "turnMaxSec": 60669 }).then(670 function(entity) {671 gameByName.Alice = { id: entityGameId(entity) }672 }673 );674 });675676 it('creates a Bob game inviting Carol', function() {677 return parseCall("Alice", "createGame", {678 "slots": [679 { type: "creator" },680 { type: "open" },681 { type: "invite", displayName: "Carry" },682 ],683 "turnMaxSec": 60684 }).then(685 function(entity) {686 gameByName.Bob = { id: entityGameId(entity) }687 }688 );689 });690691 it('contains Alice\'s game for Bob', function() {692 return parseCall("Bob", "listInvites", {693 limit: 1694 }).then(695 function(entity) {696 var result = entityResult(entity);697 result.should.have.property("games");698 699 var games = result.games;700 games.should.have.length(1);701702 var game = games[0];703 game.objectId.should.equal(gameByName.Alice.id);704 }705 )706 })707708 it('contains Bob\'s and Alice\'s game for Carol', function() {709 return parseCall("Carol", "listInvites", {710 limit: 2711 }).then(712 function(entity) {713 var result = entityResult(entity);714 result.should.have.property("games");715 716 var games = result.games;717 games.should.have.length(2);718719 games[0].objectId.should.equal(gameByName.Bob.id);720 games[1].objectId.should.equal(gameByName.Alice.id);721 }722 )723 })724725 })726727 })728729730 describe('two user game', function() {731732 var gameByName = {};733 var game = {};734 var gameBob = {};735736 it('creates a game and gets the game id with Alice', function() {737 return parseCall("Alice", "createGame", {738 "slots": [739 { "type": "creator" },740 { "type": "open" },741 { "type": "none" },742 { "type": "none" }743 ],744 "fameCards": { "The Chinatown Connection": 3 },745 "turnMaxSec": 60746 }).then(747 function(entity) {748 game.id = entityGameId(entity);749 var result = entityResult(entity, constants.t.GAME_CREATED);750 result.game.state.should.equal(GameState.Lobby);751752 var config = result.game.config;753 config.playerNum.should.equal(2);754 config.isRandom.should.equal(true);755 config.fameCards.should.have.property("The Chinatown Connection");756 config.fameCards["The Chinatown Connection"].should.equal(3);757 config.turnMaxSec.should.equal(60);758 gameByName.Alice = game.id;759 }760 );761 });762763 764 it('gets an invite link with Alice', function() {765 return parseCall("Alice", "getInvite", {766 "gameId": game.id767 }).then(768 function(entity) {769 var result = entityResult(entity, constants.t.GAME_INVITE);770 result.should.have.property("link");771 game.invite = result.link;772 result.should.have.deep.property("invite.objectId");773 result.link.should.equal(constants.INVITE_URL_PREFIX + result.invite.objectId);774 }775 );776 });777778779 it('gets the same invite link with Alice', function() {780 return parseCall("Alice", "getInvite", {781 "gameId": game.id782 }).then(783 function(entity) {784 var result = entityResult(entity, constants.t.GAME_INVITE);785 result.should.have.property("link");786 result.link.should.equal(game.invite);787 }788 );789 });790791 getGame("Alice", game, '', function(game) {792 should.exist(game);793 game.state.should.equal(GameState.Lobby);794 game.turn.should.equal(0);795796 game.should.have.property("freeSlots");797 game.freeSlots.should.equal(1);798 game.should.have.property("joined");799 game.joined.should.equal(true);800801 game.should.have.property("config");802 game.config.should.have.property("slots");803 var slots = game.config.slots;804 slots.should.have.length(4);805 slots[0].type.should.equal("creator");806 slots[0].filled.should.equal(true);807 slots[1].type.should.equal("open");808 slots[1].filled.should.equal(false);809 slots[2].type.should.equal("none");810 slots[2].filled.should.equal(false);811 slots[3].type.should.equal("none");812 slots[3].filled.should.equal(false);813 });814815 makeTurn("Alice", game, "invalid");816 makeTurn("Bob", game, "invalid");817 makeTurn("Carol", game, "invalid");818819 joinGame("Alice", game,820 "should fail joining Alice as it's her game",821 resultShouldError(constants.t.PLAYER_ALREADY_IN_GAME)822 );823 824 joinGame("Bob", game);825826827 getGame("Alice", game, '', function(game) {828 game.state.should.equal(GameState.Running);829 game.turn.should.equal(0);830 });831832 joinGame("Carol", game,833 "should fail joining Carol as the game is running",834 resultShouldError(constants.t.GAME_INVALID_STATE)835 );836837 it('creates another game with Bob', function() {838 return parseCall("Bob", "createGame", {839 "slots": [840 { "type": "creator" },841 { "type": "open" },842 { "type": "open" },843 { "type": "open" }844 ],845 "fameCards": { "The Chinatown Connection": 3 },846 "turnMaxSec": 60847 }).then(848 function(entity) {849 gameByName.Bob = gameBob.id = entityGameId(entity);850 }851 );852 });853854 getGame(855 "Bob",856 gameBob,857 'should return one free slot for game',858 function(game) {859 should.exist(game);860 game.should.have.property("freeSlots");861 game.freeSlots.should.equal(3);862 game.should.have.property("joined");863 game.joined.should.equal(true);864 }865 );866867868 var turnNumber = 0;869870 makeTurn("Bob", game, "deny", turnNumber);871872 it('should error on missing game turn save', function() {873 return parseCall('Alice', "gameTurn", {874 gameId: game.id875 }).then(876 function(entity) {877 entityError(entity, constants.t.TURN_INVALID_SAVE);878 }879 );880 });881 882 it('should error on undefined game turn save', function() {883 return parseCall('Alice', "gameTurn", {884 gameId: game.id,885 save: undefined886 }).then(887 function(entity) {888 entityError(entity, constants.t.TURN_INVALID_SAVE);889 }890 );891 });892893 it('should error on null game turn save', function() {894 return parseCall('Alice', "gameTurn", {895 gameId: game.id,896 save: null897 }).then(898 function(entity) {899 entityError(entity, constants.t.TURN_INVALID_SAVE);900 }901 );902 });903904 it('should error on empty game turn save', function() {905 return parseCall('Alice', "gameTurn", {906 gameId: game.id,907 save: ""908 }).then(909 function(entity) {910 entityError(entity, constants.t.TURN_INVALID_SAVE);911 }912 );913 });914915 it('should error on wrong type game turn save', function() {916 return parseCall('Alice', "gameTurn", {917 gameId: game.id,918 save: 12345919 }).then(920 function(entity) {921 entityError(entity, constants.t.TURN_INVALID_SAVE);922 }923 );924 });925926 makeTurn("Alice", game, "allow", turnNumber++);927 makeTurn("Alice", game, "deny", turnNumber);928 makeTurn("Bob", game, "allow", turnNumber++);929 makeTurn("Bob", game, "deny", turnNumber);930 makeTurn("Alice", game, "allow", turnNumber++);931 makeTurn("Bob", game, "allow", turnNumber++);932 makeTurn("Alice", game, "allow", turnNumber++);933 makeTurn("Bob", game, "allow", turnNumber++);934 makeTurn("Bob", game, "deny", turnNumber);935936 937 it('denies listing of turns by Carol', function() {938 return parseCall("Carol", "listTurns", {939 gameId: game.id,940 limit: 100,941 skip: 0942 }).then(resultShouldError(constants.t.TURN_THIRD_PARTY));943 });944945 it('gets the latest turn with Alice', function() {946 return parseCall("Alice", "listTurns", {947 gameId: game.id,948 limit: 1949 }).then(950 function(entity) {951 var result = entityResult(entity);952 result.should.have.property("turns");953 result.turns.should.have.length(1);954 var turn = result.turns[0];955 turn.turn.should.equal(5);956 turn.save.should.equal("turn 5");957 turn.player.user.displayName.should.equal("Bobzor");958 }959 );960 });961962 it('gets two turns in the middle with Alice', function() {963 return parseCall("Alice", "listTurns", {964 gameId: game.id,965 limit: 2,966 skip: 1967 }).then(968 function(entity) {969 var result = entityResult(entity);970 result.should.have.property("turns");971 result.turns.should.have.length(2);972973 var turnAlice = result.turns[0];974 turnAlice.player.user.displayName.should.equal("Ally");975 turnAlice.turn.should.equal(4);976977 var turnBob = result.turns[1];978 turnBob.player.user.displayName.should.equal("Bobzor");979 turnBob.turn.should.equal(3);980 }981 );982 });983984985 it('gets a valid list of all turns with Bob', function() {986 return parseCall("Bob", "listTurns", {987 gameId: game.id,988 limit: 100,989 skip: 0990 }).then(991 function(entity) {992 var result = entityResult(entity);993 result.should.have.property("turns");994 result.turns.forEach(function(turn) {995 turn.save.should.equal("turn " + turn.turn);996 turn.player.user.displayName.should.equal(997 turn.turn%2 === 0 ? "Ally" : "Bobzor"998 );999 }, this);1000 }1001 );1002 });100310041005 getGame("Bob", game, '', function(game) {1006 game.state.should.equal(GameState.Running);1007 game.turn.should.equal(6);1008 });10091010 function matchGameId(name, gameNeedle) {1011 listGames(1012 name,1013 null,1014 'should return created game id in the list of games to ' + name,1015 function(games) {1016 games.some(function(game) {1017 return game.objectId == gameNeedle.id;1018 }).should.equal(true);1019 }1020 );10211022 listGames(1023 name,1024 null,1025 'should not return a 3rd party game to ' + name,1026 function(games) {1027 function gameMatcher(matcher, game) {1028 return game.id == ngame;1029 }10301031 for (var gname in gameByName) {1032 var ngame = gameByName[gname];1033 if (gname != name && ngame != gameNeedle.id) {1034 games.some(gameMatcher.bind(this, gname)).should.equal(false);1035 }1036 }1037 }1038 );1039 }1040 1041 matchGameId('Alice', game);1042 matchGameId('Bob', game);10431044 makeTurn("Alice", game, "finish", turnNumber++);10451046 getGame("Bob", game, 'should get the ended game state with one more turn', function(game) {1047 game.state.should.equal(GameState.Ended);1048 game.turn.should.equal(7);1049 });10501051 makeTurn("Alice", game, "invalid");1052 makeTurn("Bob", game, "invalid");1053 makeTurn("Carol", game, "invalid");1054 makeTurn("Dan", game, "invalid");1055 1056 listGames("Alice", [game],1057 "test",1058 function(games) {1059 games.should.have.length(1);1060 var bobSlot = games[0].config.slots[1];1061 bobSlot.filled.should.equal(true);1062 bobSlot.should.have.deep.property('player.user.displayName');1063 bobSlot.player.user.displayName.should.equal('Bobzor');1064 }1065 );1066 1067 leaveGame("Bob", game);1068 1069 listGames("Alice", [game],1070 "test",1071 function(games) {1072 games.should.have.length(1);1073 var bobSlot = games[0].config.slots[1];1074 bobSlot.filled.should.equal(true);1075 bobSlot.should.have.deep.property('player.user.displayName');1076 bobSlot.player.user.displayName.should.equal('Bobzor');1077 }1078 );10791080 });108110821083 describe('typeId filtering', function() {10841085 var gameDefault = {};1086 var gameTypeOne = { typeId: 1 };10871088 purgeRandom();10891090 it('creates a default id game with Alice', function() {1091 return parseCall("Alice", "createGame", {1092 "slots": [1093 { "type": "creator" },1094 { "type": "open" },1095 { "type": "none" },1096 { "type": "none" }1097 ],1098 "turnMaxSec": 601099 }).then(1100 function(entity) {1101 gameDefault.id = entityGameId(entity);1102 var result = entityResult(entity, constants.t.GAME_CREATED);1103 result.game.state.should.equal(GameState.Lobby);1104 }1105 );1106 });11071108 it('creates a typeId 1 game with Alice', function() {1109 return parseCall("Alice", "createGame", {1110 "typeId": gameTypeOne.typeId,1111 "slots": [1112 { "type": "creator" },1113 { "type": "open" },1114 { "type": "none" },1115 { "type": "none" }1116 ],1117 "turnMaxSec": 601118 }).then(1119 function(entity) {1120 gameTypeOne.id = entityGameId(entity);1121 var result = entityResult(entity, constants.t.GAME_CREATED);1122 result.game.state.should.equal(GameState.Lobby);1123 }1124 );1125 });11261127 getGame("Alice", gameDefault, 'does not return a typeId for Alice', function(game) {1128 should.exist(game);11291130 game.should.have.property("config");1131 game.config.should.not.have.property("typeId");1132 });11331134 listGames("Alice", [gameDefault],1135 "should return the game in the list of active games for Alice",1136 function(games) {1137 games.should.have.length(1);1138 gameDefault.id.should.equal(games[0].objectId);1139 }1140 );11411142 listGames("Alice", [gameTypeOne],1143 "should not return typeId 1 game in the list of default active games for Alice",1144 function(games) {1145 games.should.have.length(0);1146 }1147 );11481149 getGame("Alice", gameTypeOne, 'does return typeId 1 for Alice if requested', function(game) {1150 should.exist(game);11511152 game.should.have.property("config");1153 game.config.should.have.property("typeId");1154 game.config.typeId.should.equal(1);1155 });11561157 listGames("Alice", { typeId: 1, games: [gameTypeOne] },1158 "should return typeId 1 game when filtered to typeId 1 games for Alice",1159 function(games) {1160 games.should.have.length(1);1161 gameTypeOne.id.should.equal(games[0].objectId);1162 }1163 );11641165 it('finds only the default game by default with Bob', function() {1166 return parseCall("Bob", "findGames", {}).then(1167 function(entity) {1168 var result = entityResult(entity, constants.t.GAME_LIST);1169 result.should.have.property("games");1170 result.games.should.have.length(1);1171 gameDefault.id.should.equal(result.games[0].objectId);1172 }1173 );1174 });11751176 it('finds only the typeId 1 game when filtered with Bob', function() {1177 return parseCall("Bob", "findGames", { typeId: 1 }).then(1178 function(entity) {1179 var result = entityResult(entity, constants.t.GAME_LIST);1180 result.should.have.property("games");1181 result.games.should.have.length(1);1182 gameTypeOne.id.should.equal(result.games[0].objectId);1183 }1184 );1185 });11861187 });11881189 describe('find games', function() {11901191 var gameInfos = [];1192 var gameToJoin = {};1193 var gameNum = 7;11941195 purgeRandom();11961197 it('finds no games with Bob after all of them are removed', function() {1198 return parseCall("Bob", "findGames", {1199 }).then(1200 function(entity) {1201 var result = entityResult(entity, constants.t.GAME_LIST);1202 result.should.have.property("games");1203 result.games.should.have.length(0);1204 }1205 );1206 });12071208 function createRandomGame(gameInfos) {1209 return parseCall("Alice", "createGame", {1210 "fameCards": { "The Chinatown Connection": 3 },1211 "turnMaxSec": 601212 }).then(1213 function(entity) {1214 var gameInfo = entityResult(entity, constants.t.GAME_CREATED);1215 gameInfo.should.have.property("game");1216 gameInfos.push(gameInfo);1217 }1218 );1219 }1220 1221 for (var gameIndex = 0; gameIndex < gameNum; gameIndex++) {1222 it('should make Alice create random game #' + (gameIndex + 1) + ' and get the result', createRandomGame.bind(null, gameInfos));1223 }12241225 it('finds random games with Bob that match the above', function() {1226 return parseCall("Bob", "findGames", {1227 }).then(1228 function(entity) {1229 var result = entityResult(entity, constants.t.GAME_LIST);1230 should.not.exist(result.playerCount);1231 result.should.have.property("games");1232 var games = result.games;1233 games.should.have.length(gameNum);1234 for (var gameIndex = 0; gameIndex < gameNum; gameIndex++) {1235 var game = games[gameIndex];1236 should.exist(game);1237 game.should.have.property("objectId");1238 game.objectId.should.equal(gameInfos[gameIndex].game.objectId);1239 game.joined.should.equal(false);1240 }1241 }1242 );1243 });12441245 it('finds the first three games with Bob', function() {1246 return parseCall("Bob", "findGames", {1247 "limit": 31248 }).then(1249 function(entity) {1250 var result = entityResult(entity, constants.t.GAME_LIST);1251 should.not.exist(result.playerCount);1252 result.should.have.property("games");1253 var games = result.games;1254 games.should.have.length(3);1255 for (var gameIndex = 0; gameIndex < 3; gameIndex++) {1256 games.should.have.property(gameIndex);1257 var game = games[gameIndex];1258 game.should.have.property("objectId");1259 game.objectId.should.equal(gameInfos[gameIndex].game.objectId);1260 }1261 }1262 );1263 });12641265 it('finds the next three games with Bob', function() {1266 return parseCall("Bob", "findGames", {1267 "limit": 3,1268 "skip": 31269 }).then(1270 function(entity) {1271 var result = entityResult(entity, constants.t.GAME_LIST);1272 should.not.exist(result.playerCount);1273 result.should.have.property("games");1274 var games = result.games;1275 games.should.have.length(3);1276 for (var gameIndex = 0; gameIndex < 3; gameIndex++) {1277 games.should.have.property(gameIndex);1278 var game = games[gameIndex];1279 game.should.have.property("objectId");1280 game.objectId.should.equal(gameInfos[3 + gameIndex].game.objectId);1281 }1282 }1283 );1284 });12851286 1287 it('finds the one random game to join with Bob', function() {1288 return parseCall("Bob", "findGames", {1289 "limit": 1,1290 "skip": 1,1291 }).then(1292 function(entity) {1293 var result = entityResult(entity, constants.t.GAME_LIST);1294 should.not.exist(result.playerCount);1295 result.should.have.property("games");1296 var games = result.games;1297 games.should.have.length(1);1298 var game = games[0];1299 should.exist(game);1300 game.should.have.property("objectId");1301 game.objectId.should.equal(gameInfos[1].game.objectId);1302 game.joined.should.equal(false);1303 gameToJoin.id = game.objectId;1304 }1305 );1306 });13071308 joinGame("Bob", gameToJoin, "should try joining the found game with Bob");1309 joinGame("Bob", gameToJoin,1310 "should not be able to join twice",1311 resultShouldError(constants.t.PLAYER_ALREADY_IN_GAME)1312 );13131314 it('verified joined status for three games', function() {1315 return parseCall("Bob", "findGames", {1316 "limit": 3,1317 "skip": 01318 }).then(1319 function(entity) {1320 var result = entityResult(entity, constants.t.GAME_LIST);1321 var games = result.games;1322 for (var gameIndex = 0; gameIndex < 3; gameIndex++) {1323 var game = games[gameIndex];1324 game.joined.should.equal(gameIndex == 1);1325 }1326 }1327 );1328 });13291330 describe('free slots', function() {13311332 function createGameSlotsCheck(entity) {1333 var gameInfo = entityResult(entity, constants.t.GAME_CREATED);1334 gameInfo.game.config.should.have.property("slots");1335 game.id = gameInfo.game.objectId;1336 }1337 function createGameSlots(game, slots, desc, resultFunc) {1338 if (!desc) desc = "create game with " + slots.length + " slots";1339 it(desc, function() {1340 return parseCall("Alice", "createGame", {1341 "slots": slots1342 }).then(1343 function(entity) {1344 if (resultFunc) resultFunc(entity);1345 else createGameSlotsCheck(entity);1346 }1347 );1348 });1349 }13501351 function checkFreeSlots(game, desc, playerNum) {1352 it("should equal " + playerNum + " for " + desc, function() {1353 return parseCall("Alice", "findGames", {}).then(1354 function(entity) {1355 var result = entityResult(entity, constants.t.GAME_LIST);1356 result.should.have.property("games");1357 if (playerNum == -1) {1358 result.games.length.should.equal(0);1359 } else {1360 result.games.length.should.equal(1);1361 result.games[0].freeSlots.should.equal(playerNum);1362 }1363 }1364 );1365 });1366 }13671368 var game = {};1369 function testGameSlots(desc, playerNum, slots) {1370 purgeRandom();1371 createGameSlots(game, desc, slots);1372 checkFreeSlots(game, playerNum);1373 }1374 1375 purgeRandom();1376 createGameSlots(game, [1377 { type: "creator" },1378 { type: "none" },1379 { type: "none" },1380 { type: "none" }1381 ]);1382 checkFreeSlots(game, 'game with no open slots', -1);1383 1384 purgeRandom();1385 createGameSlots(game, [1386 { type: "creator" },1387 { type: "open" },1388 { type: "none" },1389 { type: "none" }1390 ]);1391 checkFreeSlots(game, 'game with one open slot', 1);13921393 purgeRandom();1394 createGameSlots(game, [1395 { type: "creator" },1396 { type: "open" },1397 { type: "open" },1398 { type: "none" }1399 ]);1400 checkFreeSlots(game, 'game with two open slots', 2);14011402 purgeRandom();1403 createGameSlots(game, [1404 { type: "creator" },1405 { type: "open" },1406 { type: "invite", displayName: "Bobzor" },1407 { type: "none" }1408 ]);1409 checkFreeSlots(game, 'game with one open slot and one invite slot', 1);1410 1411 purgeRandom();1412 createGameSlots(game, [1413 { type: "creator" },1414 { type: "open" },1415 { type: "open" },1416 { type: "open" }1417 ]);1418 joinGame("Bob", game);1419 checkFreeSlots(game, 'game with three open slots, one filled', 2);1420 1421 purgeRandom();1422 createGameSlots(game, [1423 { type: "creator" },1424 { type: "open" },1425 { type: "invite", displayName: "Bobzor" },1426 { type: "open" }1427 ]);1428 joinGame("Bob", game);1429 joinGame("Carol", game);1430 checkFreeSlots(game, 'game with one invite, two open slots, one filled', 1);1431 1432 purgeRandom();1433 createGameSlots(game, [1434 { type: "creator" },1435 { type: "open" },1436 { type: "invite", displayName: "Bobzor" },1437 { type: "invite", displayName: "Carry" },1438 ]);1439 joinGame("Bob", game);1440 joinGame("Carol", game);1441 checkFreeSlots(game, 'game with two invites, one open', 1);1442 1443 purgeRandom();1444 createGameSlots(game, [1445 { type: "creator" },1446 { type: "invite", displayName: "Bobzor" },1447 { type: "invite", displayName: "Bobzor" },1448 { type: "open" }1449 ], "duplicate invites should error", resultShouldError(constants.t.GAME_INVALID_CONFIG));1450145114521453 purgeRandom();1454 createGameSlots(game, [1455 { type: "creator" },1456 { type: "open" },1457 { type: "ai", difficulty: 2 },1458 { type: "open" }1459 ]);1460 joinGame("Bob", game);1461 checkFreeSlots(game, 'game with two open, one ai', 1);14621463 function checkSlots(game) {1464 game.should.have.property("config");1465 var config = game.config;1466 config.should.have.property("slots");1467 var slots = config.slots;1468 slots.should.have.length(4);14691470 slots[0].type.should.equal("creator");1471 slots[0].filled.should.equal(true);1472 slots[0].should.have.property("player");1473 slots[0].player.should.have.property("user");1474 slots[0].player.user.displayName.should.equal("Ally");14751476 slots[1].type.should.equal("open");1477 slots[1].filled.should.equal(true);1478 slots[1].should.have.property("player");1479 slots[1].player.should.have.property("user");1480 slots[1].player.user.displayName.should.equal("Bobzor");14811482 slots[2].type.should.equal("ai");1483 slots[2].filled.should.equal(true);1484 slots[2].should.not.have.property("player");1485 slots[2].difficulty.should.equal(2);14861487 slots[3].type.should.equal("open");1488 slots[3].filled.should.equal(false);1489 slots[3].should.not.have.property("player");1490 }14911492 checkFreeSlots(game, 'game with one ai slot, two open slots, one filled', 1);1493 it("should have the right slot config returned", function() {1494 return parseCall("Alice", "findGames", {}).then(1495 function(entity) {1496 var result = entityResult(entity, constants.t.GAME_LIST);1497 result.should.have.property("games");1498 result.games.length.should.equal(1);1499 var game = result.games[0];1500 checkSlots(game);1501 }1502 );1503 });1504 it("should have the right slot config returned with listGames too", function() {1505 return parseCall("Alice", "listGames", { "limit": 1 }).then(1506 function(entity) {1507 var result = entityResult(entity, constants.t.GAME_LIST);1508 result.should.have.property("games");1509 result.games.length.should.equal(1);1510 var game = result.games[0];1511 checkSlots(game);1512 }1513 );1514 });15151516 15171518 purgeRandom();1519 createGameSlots(game, [1520 { type: "creator" },1521 { type: "open" },1522 { type: "none" },1523 { type: "open" }1524 ]);1525 joinGame("Bob", game);1526 checkFreeSlots(game, 'game with two open, one none', 1);152715281529153015311532 });153315341535 });153615371538 describe("start game", function() {15391540 var game = {};1541 var nonstarterGame = {};15421543 it('creates a game and gets the game id with Alice', function() {1544 return parseCall("Alice", "createGame", {1545 "slots": [1546 { "type": "creator" },1547 { "type": "open" },1548 { "type": "open" }1549 ],1550 "fameCards": { "The Chinatown Connection": 3 },1551 "turnMaxSec": 601552 }).then(1553 function(entity) {1554 game.id = entityGameId(entity);1555 game.startTime = Date.now();1556 }1557 );1558 });15591560 it('creates a game and gets the game id with Bob', function() {1561 return parseCall("Bob", "createGame", {1562 "slots": [1563 { "type": "creator" },1564 { "type": "open" },1565 { "type": "open" }1566 ],1567 "fameCards": { "The Chinatown Connection": 3 },1568 "turnMaxSec": 601569 }).then(1570 function(entity) {1571 nonstarterGame.id = entityGameId(entity);1572 nonstarterGame.startTime = Date.now();1573 }1574 );1575 });15761577 joinGame("Bob", game);1578 1579 startGame("Alice", game,1580 'should not allow Alice to start the game already',1581 resultShouldError(constants.t.GAME_NOT_STARTABLE)1582 );15831584 startGame("Bob", game,1585 'should not allow Bob to start the Alice game',1586 resultShouldError(constants.t.GAME_THIRD_PARTY)1587 );15881589 startGame("Bob", nonstarterGame,1590 'should not allow Bob to start his game already',1591 resultShouldError(constants.t.GAME_NOT_STARTABLE)1592 );1593 1594 waitAndStartGame("Bob", nonstarterGame,1595 'should not allow Bob to start a game with just himself',1596 resultShouldError(constants.t.GAME_INSUFFICIENT_PLAYERS)1597 );1598 1599 waitAndStartGame("Bob", game,1600 'should not allow a non-creator to start the game',1601 resultShouldError(constants.t.GAME_THIRD_PARTY)1602 );16031604 waitAndStartGame("Alice", game,1605 'should allow Alice to start the game after the timeout'1606 );1607 1608 waitAndStartGame("Bob", game,1609 'should not allow Bob to start the game after Alice',1610 resultShouldError(constants.t.GAME_THIRD_PARTY)1611 );16121613 waitAndStartGame("Alice", game,1614 'should not allow Alice to start the game twice',1615 resultShouldError(constants.t.GAME_NOT_STARTABLE)1616 );1617 1618 });1619162016211622 describe("leave game", function() {16231624 var game = {};1625 1626 it('creates a game and gets the game id with Alice', function() {1627 return parseCall("Alice", "createGame", {1628 "slots": [1629 { "type": "creator" },1630 { "type": "open" },1631 { "type": "open" }1632 ],1633 "fameCards": { "The Chinatown Connection": 3 },1634 "turnMaxSec": 71635 }).then(1636 function(entity) {1637 game.id = entityGameId(entity);1638 }1639 );1640 });16411642 leaveGame("Bob", game,1643 "should not allow Bob to leave a game he's not in",1644 resultShouldError(constants.t.PLAYER_NOT_IN_GAME)1645 );16461647 joinGame("Bob", game);1648 joinGame("Carol", game);16491650 var turnNumber = 0;16511652 makeTurn("Bob", game, "deny", turnNumber);1653 makeTurn("Carol", game, "deny", turnNumber);1654 makeTurn("Alice", game, "allow", turnNumber++);1655 makeTurn("Alice", game, "deny", turnNumber);1656 makeTurn("Bob", game, "allow", turnNumber++);1657 makeTurn("Bob", game, "deny", turnNumber);1658 makeTurn("Carol", game, "allow", turnNumber++);1659 makeTurn("Alice", game, "allow", turnNumber++);1660 makeTurn("Bob", game, "allow", turnNumber++);1661 makeTurn("Carol", game, "allow", turnNumber++);1662 16631664 listGames("Alice", [game],1665 "should return the game in the list of active games for Alice",1666 function(games) {1667 games.should.have.length(1);1668 game.id.should.equal(games[0].objectId);1669 }1670 );167116721673 leaveGame("Alice", game);1674 1675 listGames("Alice", [game],1676 "should remove the game from the list of active games for Alice",1677 function(games) {1678 games.should.have.length(0);1679 }1680 );1681 1682 listGames("Bob", [game],1683 "should change the Alice slot type to AI",1684 function(games) {1685 games.should.have.length(1);1686 1687 var slots = games[0].config.slots;1688 slots.should.have.length(3);1689 slots[0].type.should.equal("ai");1690 slots[0].filled.should.equal(true);1691 slots[0].should.have.deep.property("player.user.displayName");1692 slots[0].player.user.displayName.should.equal("Ally");1693 }1694 );16951696 leaveGame("Alice", game,1697 "should not allow Alice to leave the game twice",1698 resultShouldError(constants.t.PLAYER_NOT_IN_GAME)1699 );17001701 makeTurn("Alice", game, "deny", turnNumber);1702 makeTurn("Carol", game, "deny", turnNumber);1703 makeTurn("Bob", game, "allow", turnNumber++);17041705 joinGame("Alice", game,1706 "should not allow Alice to rejoin",1707 resultShouldError(constants.t.GAME_INVALID_STATE)1708 );1709 leaveGame("Bob", game);17101711 listGames("Carol", [game],1712 "should change the Bob slot type to AI",1713 function(games) {1714 games.should.have.length(1);1715 1716 var slots = games[0].config.slots;1717 slots.should.have.length(3);1718 slots[1].type.should.equal("ai");1719 }1720 );17211722 leaveGame("Bob", game,1723 "should not allow Bob to leave the game twice",1724 resultShouldError(constants.t.PLAYER_NOT_IN_GAME)1725 );1726 joinGame("Bob", game,1727 "should not allow Bob to rejoin",1728 resultShouldError(constants.t.GAME_INVALID_STATE)1729 );17301731 it("should keep the game alive with one player left", function() {1732 return parseCall({ useMasterKey: true }, "debugGame", {1733 gameId: game.id1734 }).then(1735 function(entity) {1736 var result = entityResult(entity);1737 result.state.should.equal(GameState.Running);1738 }1739 );1740 });17411742 leaveGame("Carol", game);17431744 it("should destroy the game after the last player leaves", function() {1745 return parseCall({ useMasterKey: true }, "debugGame", {1746 gameId: game.id1747 }).then(1748 function(entity) {1749 entityError(entity, constants.t.GAME_NOT_FOUND);1750 }1751 );1752 });17531754 describe("before starting", function() {1755 1756 var game = {};17571758 it('creates a game and gets the game id with Alice', function() {1759 return parseCall("Alice", "createGame", {1760 "slots": [1761 { "type": "creator" },1762 { "type": "open" },1763 { "type": "open" },1764 { "type": "open" }1765 ],1766 "turnMaxSec": 101767 }).then(1768 function(entity) {1769 game.id = entityGameId(entity);1770 }1771 );1772 });1773 joinGame("Bob", game);1774 leaveGame("Bob", game, "with Bob");17751776 listGames("Alice", [game],1777 "should keep it running after Bob leaves",1778 function(games) {1779 games.should.have.length(1);1780 1781 var slots = games[0].config.slots;1782 slots.should.have.length(4);1783 slots[1].type.should.equal("open");1784 slots[1].filled.should.equal(true);1785 slots[1].should.have.deep.property("player.user.displayName");1786 slots[1].player.user.displayName.should.equal("Bobzor");1787 slots[1].player.state.should.equal(PlayerState.Inactive);1788 }1789 );17901791 joinGame("Carol", game);17921793 leaveGame("Alice", game, "with Alice");1794 1795 it("should end the game", function() {1796 return parseCall({ useMasterKey: true }, "debugGame", {1797 gameId: game.id1798 }).then(1799 function(entity) {1800 var result = entityResult(entity);1801 result.state.should.equal(GameState.Ended);1802 }1803 );1804 });18051806 });18071808 });18091810 describe("two user, then solo game", function() {1811 1812 var game = {};18131814 it('creates a game and gets the game id with Alice', function() {1815 return parseCall("Alice", "createGame", {1816 "slots": [1817 { "type": "creator" },1818 { "type": "open" }1819 ],1820 "fameCards": {},1821 "turnMaxSec": 601822 }).then(1823 function(entity) {1824 game.id = entityGameId(entity);1825 }1826 );1827 });18281829 makeTurn("Alice", game, "invalid");1830 makeTurn("Bob", game, "invalid");18311832 joinGame("Bob", game);18331834 var turnNumber = 0;18351836 makeTurn("Alice", game, "allow", turnNumber++);1837 makeTurn("Bob", game, "allow", turnNumber++);1838 makeTurn("Alice", game, "allow", turnNumber++);1839 makeTurn("Bob", game, "allow", turnNumber++);1840 makeTurn("Alice", game, "allow", turnNumber++);1841 makeTurn("Bob", game, "allow", turnNumber++);1842 1843 getGame("Bob", game, 'should be running before Alice leaves', (function(turn, game) {1844 game.state.should.equal(GameState.Running);1845 game.turn.should.equal(turn);1846 }).bind(this, turnNumber++));18471848 leaveGame("Alice", game, null);18491850 getGame("Bob", game, 'should keep running after Alice leaves', (function(turn, game) {1851 game.state.should.equal(GameState.Running);1852 game.turn.should.equal(turn);1853 }).bind(this, turnNumber++));18541855 makeTurn("Alice", game, "deny", turnNumber);1856 makeTurn("Bob", game, "allow", turnNumber++);1857 makeTurn("Bob", game, "allow", turnNumber++);1858 makeTurn("Bob", game, "allow", turnNumber++);1859 makeTurn("Bob", game, "allow", turnNumber++);1860 makeTurn("Bob", game, "allow", turnNumber++);1861 makeTurn("Bob", game, "allow", turnNumber++);1862 makeTurn("Bob", game, "finish", turnNumber++);1863 1864 getGame("Bob", game, 'should end after finishing turn', function(game) {1865 game.state.should.equal(GameState.Ended);1866 });18671868 });18691870 describe("ai", function() {1871 describe("should copy the turn if the current player leaves", function() {1872 1873 var game = {};18741875 it('creates a game and gets the game id with Alice', function() {1876 return parseCall("Alice", "createGame", {1877 "slots": [1878 { "type": "creator" },1879 { "type": "open" },1880 { "type": "open" }1881 ],1882 "turnMaxSec": 101883 }).then(1884 function(entity) {1885 game.id = entityGameId(entity);1886 }1887 );1888 });1889 joinGame("Bob", game);1890 joinGame("Carol", game);18911892 turnNumber = 0;18931894 makeTurn("Alice", game, "allow", turnNumber++);1895 makeTurn("Bob", game, "allow", turnNumber++);1896 makeTurn("Carol", game, "allow", turnNumber++);1897 makeTurn("Alice", game, "allow", turnNumber++);18981899 leaveGame("Bob", game);19001901 it("gets the copied turn", function() {1902 return parseCall("Alice", "listTurns", {1903 gameId: game.id,1904 limit: 21905 }).then(1906 function(entity) {1907 var result = entityResult(entity, constants.t.TURN_LIST);1908 var turns = result.turns;1909 turns[0].turn.should.equal(4);1910 turns[0].player.user.displayName.should.equal("Bobzor");1911 turns[1].turn.should.equal(3);1912 turns[1].player.user.displayName.should.equal("Ally");1913 turns[0].save.should.equal(turns[1].save);1914 turns[0].save.should.equal("turn 3");1915 }1916 );1917 })19181919 listGames("Alice", [game],1920 "should turn to AI and advance to the next player",1921 function(games) {1922 games.should.have.length(1);1923 var gameResult = games[0];1924 game.id.should.equal(gameResult.objectId);192519261927 var slots = gameResult.config.slots;1928 slots.should.have.length(3);1929 slots[1].type.should.equal(constants.SlotType.AI);1930 1931 var currentPlayer = gameResult.currentPlayer;1932 currentPlayer.user.displayName.should.equal("Carry");1933 }1934 ); 1935 1936 });19371938 if (testTimeouts) describe("should copy the turn if the current player times out", function() {1939 1940 var game = {};1941 var turnMaxSec = 5;19421943 it('creates a game and gets the game id with Alice', function() {1944 return parseCall("Alice", "createGame", {1945 "slots": [1946 { "type": "creator" },1947 { "type": "open" },1948 { "type": "open" }1949 ],1950 "turnMaxSec": turnMaxSec1951 }).then(1952 function(entity) {1953 game.id = entityGameId(entity);1954 }1955 );1956 });1957 joinGame("Bob", game);1958 joinGame("Carol", game);19591960 turnNumber = 0;19611962 makeTurn("Alice", game, "allow", turnNumber++);1963 makeTurn("Bob", game, "allow", turnNumber++);1964 makeTurn("Carol", game, "allow", turnNumber++);1965 makeTurn("Alice", game, "allow", turnNumber++);1966 1967 it("waits for turn to time out", function() {1968 var promise = new Promise();1969 setTimeout(function() {1970 promise.resolve();1971 }, turnMaxSec*1000 + 1000);1972 this.timeout(turnMaxSec*1000 + 2000);1973 return promise;1974 })19751976 it("gets the copied turn", function() {1977 return parseCall("Alice", "listTurns", {1978 gameId: game.id,1979 limit: 21980 }).then(1981 function(entity) {1982 var result = entityResult(entity, constants.t.TURN_LIST);1983 var turns = result.turns;1984 turns[0].turn.should.equal(4);1985 turns[0].player.user.displayName.should.equal("Bobzor");1986 turns[1].turn.should.equal(3);1987 turns[1].player.user.displayName.should.equal("Ally");1988 turns[0].save.should.equal(turns[1].save);1989 turns[0].save.should.equal("turn 3");1990 }1991 );1992 })19931994 listGames("Alice", [game],1995 "should advance to the next player",1996 function(games) {1997 games.should.have.length(1);1998 var gameResult = games[0];1999 game.id.should.equal(gameResult.objectId);200020012002 var slots = gameResult.config.slots;2003 slots.should.have.length(3);2004 slots[1].type.should.equal(constants.SlotType.AI);2005 2006 var currentPlayer = gameResult.currentPlayer;2007 currentPlayer.user.displayName.should.equal("Carry");2008 }2009 );20102011 2012 });20132014 describe("should create an empty turn for starting AI", function() {2015 2016 var game = {};2017 var turnMaxSec = 5;20182019 it('creates a game and gets the game id with Alice', function() {2020 return parseCall("Alice", "createGame", {2021 "slots": [2022 { "type": "creator" },2023 { "type": "open" },2024 { "type": "open" }2025 ],2026 "turnMaxSec": turnMaxSec2027 }).then(2028 function(entity) {2029 game.id = entityGameId(entity);2030 }2031 );2032 });2033 joinGame("Bob", game);2034 joinGame("Carol", game);20352036 leaveGame("Alice", game);20372038 it("gets the initial empty turn", function() {2039 return parseCall("Bob", "listTurns", {2040 gameId: game.id2041 }).then(2042 function(entity) {2043 var result = entityResult(entity, constants.t.TURN_LIST);2044 var turns = result.turns;2045 turns.should.have.length(1);20462047 var turn = turns[0];2048 turn.save.should.equal("");2049 turn.turn.should.equal(0);2050 }2051 );2052 })20532054 listGames("Bob", [game],2055 "should advance to the next player",2056 function(games) {2057 games.should.have.length(1);2058 var gameResult = games[0];2059 game.id.should.equal(gameResult.objectId);20602061 var slots = gameResult.config.slots;2062 slots.should.have.length(3);2063 slots[0].type.should.equal(constants.SlotType.AI);2064 2065 var currentPlayer = gameResult.currentPlayer;2066 currentPlayer.user.displayName.should.equal("Bobzor");2067 }2068 );20692070 2071 });20722073 });20742075});207620772078describe("quota", function() {2079 before(function() {2080 return Promise.when(2081 getUserSessions(),2082 purgeGames()2083 );2084 });2085 after(purgeGames);20862087 describe("create game", function() {20882089 function createGame(expected, desc) {2090 it(desc || expected.m, function() {2091 return parseCall("Alice", "createGame", {2092 "slots": [2093 { "type": "creator" },2094 { "type": "invite", "displayName": "Bobzor" },2095 { "type": "none" },2096 { "type": "open" },2097 ],2098 "fameCards": {},2099 "turnMaxSec": 602100 }).then(2101 function(entity) {2102 if (expected.id > 1000) {2103 entityError(entity, expected);2104 } else {2105 entityResult(entity, expected);2106 }2107 }2108 );2109 });2110 }21112112 function testRecentQuota(index) {2113 var min = index*constants.GAME_LIMIT_RECENT;2114 var max = Math.min(constants.GAME_LIMIT_TOTAL, (index + 1)*constants.GAME_LIMIT_RECENT);2115 for (var i = min; i < max; i++) {2116 createGame(constants.t.GAME_CREATED, "create game " + (i + 1));2117 }2118 createGame(constants.t.GAME_QUOTA_EXCEEDED, "should fail creating game due to recent quota");2119 }21202121 function waitForQuota() {2122 it("wait for the quota to expire", function() {2123 var promise = new Promise();2124 setTimeout(function() {2125 promise.resolve();2126 }, constants.GAME_LIMIT_RECENT_TIMEOUT*1000);2127 return promise;2128 })2129 }21302131 this.timeout(2000 + recencyPumps*constants.GAME_LIMIT_RECENT_TIMEOUT*1000);21322133 purgeGames();21342135 var recencyPumps = Math.ceil(constants.GAME_LIMIT_TOTAL / constants.GAME_LIMIT_RECENT);2136 for (var i = 0; i < recencyPumps; i++) {2137 testRecentQuota(i);21382139 var gameNum = Math.min(constants.GAME_LIMIT_TOTAL, (i + 1)*constants.GAME_LIMIT_RECENT);2140 it("should return " + gameNum + " games", function(gameNum) {2141 return parseCall("Alice", "listGames", {2142 limit: 1002143 }).then(2144 function(entity) {2145 var result = entityResult(entity, constants.t.GAME_LIST);2146 result.should.have.property("games");2147 result.games.should.be.an("array");2148 result.games.should.have.length(gameNum);2149 }2150 );2151 }.bind(this, gameNum))21522153 waitForQuota();2154 }21552156 createGame(constants.t.GAME_QUOTA_EXCEEDED, "should fail creating game due to total quota");21572158 })215921602161})21622163describe("users", function() {2164 before(getUserSessions);21652166 it("set avatar for Alice to 5", function() {2167 return parseCall("Alice", "userSet", {2168 avatar: 52169 }).then(2170 function(entity) {2171 entityResult(entity, constants.t.USER_SAVED);2172 }2173 );2174 });21752176 it("add Alice as friend with Bob", function() {2177 return parseCall("Bob", "addFriend", {2178 displayName: "Ally"2179 }).then(2180 function(entity) {2181 try {2182 entityResult(entity, constants.t.CONTACT_ADDED);2183 } catch(e) {2184 entityError(entity, constants.t.CONTACT_EXISTS);2185 }2186 }2187 );2188 });21892190 it("should see avatar 5 for Alice in Bob's friends", function() {2191 return parseCall("Bob", "listFriends", {}).then(2192 function(entity) {2193 var result = entityResult(entity, constants.t.CONTACT_LIST);2194 var alice = result.contacts.find(function(contact) {2195 return contact.displayName == "Ally";2196 });2197 alice.avatar.should.equal(5);2198 }2199 )2200 })22012202 it("set avatar for Alice to 1", function() {2203 return parseCall("Alice", "userSet", {2204 avatar: 12205 }).then(2206 function(entity) {2207 entityResult(entity, constants.t.USER_SAVED);2208 }2209 );2210 });2211 2212 it("should see avatar 1 for Alice in Bob's friends", function() {2213 return parseCall("Bob", "listFriends", {}).then(2214 function(entity) {2215 var result = entityResult(entity, constants.t.CONTACT_LIST);2216 var alice = result.contacts.find(function(contact) {2217 return contact.displayName == "Ally";2218 });2219 alice.avatar.should.equal(1);2220 }2221 )2222 })22232224})22252226describe("contacts", function() {2227 before(getUserSessions);22282229 function removeContacts() {2230 it("should remove contacts first", function() {2231 return parseCall({ useMasterKey: true }, "purgeContacts", {}).then(2232 function(result) {2233 result.should.have.property("result");2234 should.equal(result.result.purged, true);2235 }2236 );2237 });2238 }22392240 function contactCheck(name, desc, include, exclude, done) {2241 var nobody = !include && !exclude;2242 if (!desc) {2243 desc = nobody ?2244 'returns nobody for ' + name :2245 'returns ' + 2246 include.join(" and ") +2247 ' and not ' + exclude.join(" and ") +2248 ' as friends of ' + name;2249 }2250 it(desc, function() {2251 return parseCall(name, "listFriends", {2252 }).then(2253 function(entity) {2254 var result = entityResult(entity, constants.t.CONTACT_LIST);2255 result.should.have.property("contacts");2256 var contacts = result.contacts;2257 if (nobody) {2258 contacts.should.have.length(0);2259 } else {22602261 include.forEach(function(contactName) {2262 should.exist(contacts.find(function(contact) {2263 return contact.displayName == contactName;2264 }));2265 }, this);22662267 exclude.forEach(function(contactName) {2268 should.not.exist(contacts.find(function(contact) {2269 return contact.displayName == contactName;2270 }));2271 }, this);2272 2273 }22742275 if (done) done(contacts);2276 }2277 );2278 });2279 }22802281 function addContact(name, contactName, desc) {2282 if (!desc) {2283 desc = name + ' adds ' + contactName + ' as a friend';2284 }2285 it(desc, function() {2286 return parseCall(name, "addFriend", {2287 displayName: contactName2288 }).then(2289 function(entity) {2290 var result = entityResult(entity, constants.t.CONTACT_ADDED);2291 result.should.have.property("contact");2292 var contact = result.contact;2293 contact.contact.displayName.should.equal(contactName);2294 }2295 );2296 });2297 }22982299 function deleteContact(name, contactName, desc) {2300 if (!desc) {2301 desc = name + ' removes ' + contactName + ' from friends';2302 }2303 it(desc, function() {2304 return parseCall(name, "deleteFriend", {2305 displayName: contactName2306 }).then(2307 function(entity) {2308 entityResult(entity, constants.t.CONTACT_DELETED);2309 }2310 );2311 });2312 }23132314 function blockContact(name, contactName, desc) {2315 if (!desc) {2316 desc = name + ' blocks ' + contactName;2317 }2318 it(desc, function() {2319 return parseCall(name, "blockFriend", {2320 displayName: contactName2321 }).then(2322 function(entity) {2323 entityResult(entity, constants.t.CONTACT_BLOCKED);2324 }2325 );2326 });2327 }23282329 describe("basic", function() {2330 removeContacts();23312332 contactCheck("Alice");2333 contactCheck("Bob");2334 contactCheck("Carol");2335 contactCheck("Dan");23362337 var game = {};23382339 it('creates a game and gets the game id with Alice', function() {2340 return parseCall("Alice", "createGame", {2341 "slots": [2342 { "type": "creator" },2343 { "type": "open" },2344 { "type": "none" },2345 { "type": "open" },2346 ],2347 "fameCards": { "The Chinatown Connection": 3 },2348 "turnMaxSec": 602349 }).then(2350 function(entity) {2351 game.id = entityGameId(entity);2352 }2353 );2354 });23552356 joinGame("Bob", game, 'has Bob join game');2357 joinGame("Carol", game, 'has Carol join game');2358 2359 contactCheck("Alice");2360 contactCheck("Bob");2361 contactCheck("Carol");2362 contactCheck("Dan");23632364 addContact("Alice", "Carry");2365 contactCheck("Alice", null, ["Carry"], ["Ally", "Bobzor", "Dan the Man"]);2366 contactCheck("Carol");23672368 addContact("Bob", "Carry");2369 contactCheck("Alice", null, ["Carry"], ["Ally", "Bobzor", "Dan the Man"]);2370 contactCheck("Bob", null, ["Carry"], ["Ally", "Bobzor", "Dan the Man"]);2371 contactCheck("Carol");23722373 addContact("Carol", "Bobzor");2374 contactCheck("Alice", null, ["Carry"], ["Ally", "Bobzor", "Dan the Man"]);2375 contactCheck("Bob", null, ["Carry"], ["Ally", "Bobzor", "Dan the Man"]);2376 contactCheck("Carol", null, ["Bobzor"], ["Ally", "Carol", "Dan the Man"]);2377 contactCheck("Dan");23782379 addContact("Carol", "Dan the Man");2380 contactCheck("Carol", null, ["Bobzor", "Dan the Man"], ["Ally", "Carol"]);2381 contactCheck("Dan");23822383 deleteContact("Carol", "Bobzor");2384 contactCheck("Carol", null, ["Dan the Man"], ["Bobzor", "Ally", "Carol"]);2385 contactCheck("Dan");2386 })23872388 describe("blocking", function() {23892390 var game = {};23912392 function createGame(expected) {2393 it('creates a game and gets the game id with Alice', function() {2394 return parseCall("Alice", "createGame", {2395 "slots": [2396 { "type": "creator" },2397 { "type": "invite", "displayName": "Bobzor" },2398 { "type": "none" },2399 { "type": "open" },2400 ],2401 "fameCards": {},2402 "turnMaxSec": 602403 }).then(2404 function(entity) {2405 if (expected.id > 1000) {2406 entityError(entity, expected);2407 } else {2408 entityResult(entity, expected);2409 }2410 }2411 );2412 });2413 }24142415 describe("stranger", function() {2416 removeContacts();2417 createGame(constants.t.GAME_CREATED);2418 contactCheck("Alice");2419 contactCheck("Bob");24202421 blockContact("Bob", "Ally");2422 createGame(constants.t.GAME_PLAYERS_UNAVAILABLE);24232424 addContact("Bob", "Ally")2425 createGame(constants.t.GAME_CREATED);2426 })2427 2428 describe("friend", function() {2429 removeContacts();2430 createGame(constants.t.GAME_CREATED);2431 contactCheck("Alice");2432 contactCheck("Bob");24332434 addContact("Bob", "Ally")2435 createGame(constants.t.GAME_CREATED);24362437 blockContact("Bob", "Ally");2438 createGame(constants.t.GAME_PLAYERS_UNAVAILABLE);24392440 addContact("Bob", "Ally")2441 createGame(constants.t.GAME_CREATED);2442 })244324442445 })244624472448 2449});245024512452describe("kue", function() {2453 before(getUserSessions);24542455 2456 if (testTimeouts) describe("lobby timeout job", function() {24572458 var game = {};24592460 if (testTimeouts) it('creates a game and waits for timeout with Alice', function() {2461 return parseCall("Alice", "createGame", {2462 "slots": [2463 { "type": "creator" },2464 { "type": "open" }2465 ],2466 "fameCards": {},2467 "turnMaxSec": 602468 }).then(2469 function(entity) {2470 game.id = entityGameId(entity);2471 var result = entityResult(entity);2472 }2473 );2474 });2475 2476 it('should end the game after timeout', function() {2477 2478 var promise = new Promise();24792480 setTimeout(function() {2481 promise.resolve();2482 }, constants.START_GAME_AUTO_TIMEOUT*1000 + 1000);24832484 this.timeout(constants.START_GAME_AUTO_TIMEOUT*1000 + 2000);24852486 return promise.then(2487 function() {2488 return parseCall("Alice", "listGames", {2489 gameIds: [game.id] 2490 });2491 }2492 ).then(2493 function(entity) {2494 var result = entityResult(entity, constants.t.GAME_LIST);2495 result.should.have.property("games");2496 result.games.should.be.an("array");2497 result.games.should.have.length(1);24982499 var game = result.games[0];2500 game.state.should.equal(GameState.Ended);2501 return Promise.resolve();2502 }2503 );2504 });25052506 });25072508 2509 describe("lobby timeout skipped job", function() {25102511 var game = {};25122513 it('creates a game and gets the game id with Alice', function() {2514 return parseCall("Alice", "createGame", {2515 "slots": [2516 { "type": "creator" },2517 { "type": "open" }2518 ],2519 "fameCards": {},2520 "turnMaxSec": 602521 }).then(2522 function(entity) {2523 game.id = entityGameId(entity);2524 var result = entityResult(entity);2525 }2526 );2527 });2528 joinGame("Bob", game);25292530 it("should get deleted after game starts", function() {2531 return parseCall({ useMasterKey: true }, "debugGame", {2532 gameId: game.id2533 }).then(2534 function(entity) {2535 var result = entityResult(entity);2536 return checkDeletedJob(result.lobbyTimeoutJob);2537 }2538 );2539 });2540 });25412542 describe("turn timeout job", function() {25432544 var turnMaxSec = 1*timeoutMultiplier;2545 var game = {};25462547 it('creating a game with Alice', function() {2548 return parseCall("Alice", "createGame", {2549 "slots": [2550 { "type": "creator" },2551 { "type": "open" }2552 ],2553 "turnMaxSec": turnMaxSec2554 }).then(2555 function(entity) {2556 game.id = entityGameId(entity);2557 var result = entityResult(entity);2558 }2559 );2560 });2561 joinGame("Bob", game);25622563 it('sets job id in game', function() {2564 return parseCall({ useMasterKey: true }, "debugGame", {2565 gameId: game.id2566 }).then(2567 function(entity) {2568 var result = entityResult(entity);2569 result.should.have.property("turnTimeoutJob");2570 game.turnTimeoutJob = result.turnTimeoutJob; 2571 }2572 );2573 });2574 2575 it('should be running', function() {2576 return getJob(game.turnTimeoutJob).then(2577 function(job) {2578 job.id.should.equal(game.turnTimeoutJob);2579 }2580 );2581 });25822583 var turnNumber = 0;2584 makeTurn("Alice", game, "allow", turnNumber++);2585 2586 it("should get deleted after a turn is made", function() {2587 return checkDeletedJob(game.turnTimeoutJob);2588 });25892590 it('sets new job id in game', function() {2591 return parseCall({ useMasterKey: true }, "debugGame", {2592 gameId: game.id2593 }).then(2594 function(entity) {2595 var result = entityResult(entity);2596 result.should.have.property("turnTimeoutJob");2597 result.turnTimeoutJob.should.not.equal(game.turnTimeoutJob);2598 game.turnTimeoutJob = result.turnTimeoutJob; 2599 }2600 );2601 });26022603 makeTurn("Alice", game, "deny", turnNumber);2604 2605 if (testTimeouts) {2606 turnNumber++;2607 it("should advance to the next player after timeout", function() {2608 var promise = new Promise();2609 setTimeout(function() {2610 promise.resolve();2611 }, turnMaxSec*1000 + 1000);2612 this.timeout(turnMaxSec*1000 + 2000);26132614 return promise.then(2615 function() {2616 return parseCall({ useMasterKey: true }, "debugGame", {2617 gameId: game.id2618 });2619 }2620 ).then(2621 function(entity) {2622 var result = entityResult(entity);2623 result.should.have.property("turnTimeoutJob");2624 result.turnTimeoutJob.should.not.equal(game.turnTimeoutJob);2625 game.turnTimeoutJob = result.turnTimeoutJob;2626 }2627 );2628 });2629 makeTurn("Bob", game, "deny", turnNumber);2630 makeTurn("Alice", game, "allow", turnNumber++);26312632 if (testTimeouts) it('works together with normal turns', function() {2633 return parseCall("Alice", "listTurns", {2634 gameId: game.id,2635 limit: 42636 }).then(2637 function(entity) {2638 var result = entityResult(entity, constants.t.TURN_LIST);2639 var turns = result.turns;2640 turns.should.have.length(3);26412642 turns.forEach(function(turn, index) {2643 // Invert index (most recent is highest)2644 index = turns.length - 1 - index;2645 turn.should.have.deep.property("player.state");2646 if (index == 1) {2647 // Timeout turn2648 turn.player.state.should.equal(PlayerState.Inactive);2649 turn.save.should.equal("turn 0");2650 } else {2651 turn.player.state.should.equal(PlayerState.Active);2652 turn.save.should.equal("turn " + index);2653 }2654 }, this);2655 }2656 );2657 });2658 }26592660 makeTurn("Alice", game, "finish", turnNumber++);26612662 if (testTimeouts) it('should be different after a few turns', function() {2663 return parseCall({ useMasterKey: true }, "debugGame", {2664 gameId: game.id2665 }).then(2666 function(entity) {2667 var result = entityResult(entity);2668 result.should.have.property("turnTimeoutJob");2669 result.turnTimeoutJob.should.not.equal(game.turnTimeoutJob);2670 game.turnTimeoutJob = result.turnTimeoutJob;2671 }2672 );2673 });26742675 it('should not exist after end of game', function() {2676 return checkDeletedJob(game.turnTimeoutJob);2677 });26782679 });26802681 2682 if (testTimeouts) describe("game ending turn timeout job", function() {26832684 var slots = [2685 { "type": "creator" },2686 { "type": "open" }2687 ];2688 var turnMaxSec = 1*timeoutMultiplier;2689 var game = {};26902691 it('creating a game with Alice', function() {2692 return parseCall("Alice", "createGame", {2693 "slots": [2694 { "type": "creator" },2695 { "type": "open" }2696 ],2697 "turnMaxSec": turnMaxSec2698 }).then(2699 function(entity) {2700 game.id = entityGameId(entity);2701 var result = entityResult(entity);2702 }2703 );2704 });2705 joinGame("Bob", game);27062707 it('should be running', function() {2708 return parseCall({ useMasterKey: true }, "debugGame", {2709 gameId: game.id2710 }).then(2711 function(entity) {2712 var result = entityResult(entity);2713 result.should.have.property("turnTimeoutJob");2714 game.turnTimeoutJob = result.turnTimeoutJob;2715 return getJob(game.turnTimeoutJob); 2716 }2717 ).then(2718 function(job) {2719 job.id.should.equal(game.turnTimeoutJob);2720 }2721 );2722 });2723 2724 var turnNumber = 0;2725 makeTurn("Alice", game, "allow", turnNumber++);2726 makeTurn("Bob", game, "allow", turnNumber++);2727 makeTurn("Alice", game, "allow", turnNumber++);2728 makeTurn("Bob", game, "allow", turnNumber++);27292730 it('should still be running', function() {2731 return parseCall({ useMasterKey: true }, "debugGame", {2732 gameId: game.id2733 }).then(2734 function(entity) {2735 var result = entityResult(entity);2736 result.should.have.property("turnTimeoutJob");2737 game.turnTimeoutJob = result.turnTimeoutJob;2738 return getJob(game.turnTimeoutJob); 2739 }2740 ).then(2741 function(job) {2742 job.id.should.equal(game.turnTimeoutJob);2743 }2744 );2745 });27462747 it("should destroy the game after " + constants.GAME_ENDING_INACTIVE_ROUNDS + " inactive rounds", function() {2748 var waitMs = (turnMaxSec + 1)*slots.length*constants.GAME_ENDING_INACTIVE_ROUNDS*1000;2749 var promise = new Promise();2750 setTimeout(function() {2751 promise.resolve();2752 }, waitMs + 1000);2753 this.timeout(waitMs + 2000);27542755 return promise.then(2756 function() {2757 return parseCall({ useMasterKey: true }, "debugGame", {2758 gameId: game.id2759 });2760 }2761 ).then(2762 function(entity) {2763 entityError(entity, constants.t.GAME_NOT_FOUND);2764 }2765 );2766 });27672768 });27692770});27712772describe("cleanup", function() {2773 before(getUserSessions);2774 2775 var game = {};2776 function exists(extraDesc) {2777 extraDesc = extraDesc ? " " + extraDesc : "";2778 it('exists' + extraDesc, function() {2779 return parseCall({ useMasterKey: true }, "classes/Game/" + game.id).then(2780 function(retGame) {2781 retGame.objectId.should.equal(game.id);2782 game.jobs = [2783 retGame.turnTimeoutJob2784 ];2785 if (game.result.state == GameState.Lobby) {2786 game.jobs.push(retGame.lobbyTimeoutJob);2787 }2788 }2789 );2790 });2791 }27922793 function destroyed() {2794 it('does not exist anymore', function() {2795 return parseCall({ useMasterKey: true }, "classes/Game/" + game.id).then(2796 function(result) {2797 if (result && result.code == Parse.Error.OBJECT_NOT_FOUND) {2798 return Promise.resolve();2799 }2800 return Promise.reject(new Error("it exists"));2801 }2802 );2803 });28042805 it('jobs do not exist anymore', function() {2806 return Promise.when(game.jobs.map(2807 function(jobId) {2808 return getJob(jobId);2809 }2810 )).then(2811 function(retJobs) {2812 return Promise.reject(new Error("they exist"));2813 },2814 function() {2815 return Promise.resolve();2816 }2817 );2818 });28192820 it('turns do not exist anymore', function() {2821 this.timeout(20000);2822 return Promise.when(game.turns.map(2823 function(turn) {2824 return parseCall({ useMasterKey: true }, "classes/Turn/" + turn.objectId);2825 }2826 )).then(2827 function(results) {2828 if (results) {2829 var everyNotFound = results.every(function(result) {2830 return result.code == Parse.Error.OBJECT_NOT_FOUND;2831 });2832 if (everyNotFound) {2833 return Promise.resolve();2834 }2835 }2836 return Promise.reject(new Error("they exist"));2837 }2838 );2839 });2840 2841 it('invite does not exist anymore', function() {2842 return parseCall({ useMasterKey: true }, "classes/Invite/" + game.invite.objectId).then(2843 function(result) {2844 if (result && result.code == Parse.Error.OBJECT_NOT_FOUND) {2845 return Promise.resolve();2846 }2847 return Promise.reject(new Error("it exists"));2848 }2849 );2850 });2851 }28522853 describe("game normally", function() {28542855 it('gets created with Alice', function() {2856 return parseCall("Alice", "createGame", {2857 slots: [2858 { type: "creator" },2859 { type: "open" }2860 ]2861 }).then(2862 function(entity) {2863 game.id = entityGameId(entity);2864 game.result = entityResult(entity);2865 }2866 );2867 });2868 2869 it('provides invite link to Alice', function() {2870 return parseCall("Alice", "getInvite", {2871 "gameId": game.id2872 }).then(2873 function(entity) {2874 var result = entityResult(entity, constants.t.GAME_INVITE);2875 game.invite = result.invite;2876 }2877 );2878 });28792880 joinGame("Bob", game);28812882 var turnNumber = 0;2883 makeTurn("Alice", game, "allow", turnNumber++);2884 makeTurn("Bob", game, "allow", turnNumber++);2885 makeTurn("Alice", game, "allow", turnNumber++);2886 makeTurn("Bob", game, "allow", turnNumber++);2887 2888 it('provides turn list', function() {2889 return parseCall("Alice", "listTurns", {2890 gameId: game.id,2891 limit: 10,2892 skip: 02893 }).then(2894 function(entity) {2895 var result = entityResult(entity, constants.t.TURN_LIST);2896 game.turns = result.turns;2897 }2898 );2899 });29002901 exists();29022903 it('jobs exist', function() {2904 return Promise.when(game.jobs.map(2905 function(jobId) {2906 return getJob(jobId);2907 }2908 )).then(2909 function(retJobs) {2910 for (var jobIndex in retJobs) {2911 var jobId = game.jobs[jobIndex];2912 var retJob = retJobs[jobIndex];2913 retJob.id.should.equal(jobId);2914 }2915 }2916 );2917 });2918 2919 it('turns exist', function() {2920 return Promise.when(game.turns.map(2921 function(turn) {2922 return parseCall({ useMasterKey: true }, "classes/Turn/" + turn.objectId);2923 }2924 )).then(2925 function(retTurns) {2926 for (var turnIndex in retTurns) {2927 var turn = game.turns[turnIndex];2928 var retTurn = retTurns[turnIndex];2929 retTurn.objectId.should.equal(turn.objectId);2930 }2931 }2932 );2933 });2934 2935 it('invite exists', function() {2936 return parseCall({ useMasterKey: true }, "classes/Invite/" + game.invite.objectId).then(2937 function(retInvite) {2938 retInvite.objectId.should.equal(game.invite.objectId);2939 }2940 );2941 });294229432944 // Use leaveGame with all players to destroy the game29452946 makeTurn("Alice", game, "finish", turnNumber++);2947 exists("after finishing turn");29482949 leaveGame("Alice", game)2950 exists("after Alice leaves");29512952 leaveGame("Bob", game)29532954 destroyed();2955 });29562957 describe("game when everyone leaves mid-game", function() {2958 2959 it('gets created with Alice', function() {2960 return parseCall("Alice", "createGame", {2961 slots: [2962 { type: "creator" },2963 { type: "open" },2964 { type: "open" }2965 ]2966 }).then(2967 function(entity) {2968 game.id = entityGameId(entity);2969 game.result = entityResult(entity);2970 }2971 );2972 });2973 2974 it('provides invite link to Alice', function() {2975 return parseCall("Alice", "getInvite", {2976 "gameId": game.id2977 }).then(2978 function(entity) {2979 var result = entityResult(entity, constants.t.GAME_INVITE);2980 game.invite = result.invite;2981 }2982 );2983 });2984 2985 joinGame("Bob", game);2986 joinGame("Carol", game);29872988 var turnNumber = 0;2989 makeTurn("Alice", game, "allow", turnNumber++);2990 makeTurn("Bob", game, "allow", turnNumber++);2991 makeTurn("Carol", game, "allow", turnNumber++);2992 makeTurn("Alice", game, "allow", turnNumber++);2993 makeTurn("Bob", game, "allow", turnNumber++);2994 makeTurn("Carol", game, "allow", turnNumber++);2995 makeTurn("Alice", game, "allow", turnNumber++);2996 makeTurn("Bob", game, "allow", turnNumber++);2997 2998 it('provides turn list', function() {2999 return parseCall("Alice", "listTurns", {3000 gameId: game.id,3001 limit: 10,3002 skip: 03003 }).then(3004 function(entity) {3005 var result = entityResult(entity, constants.t.TURN_LIST);3006 game.turns = result.turns;3007 }3008 );3009 });30103011 exists();30123013 // Use leaveGame with all players to destroy the game30143015 leaveGame("Carol", game)3016 exists("after Carol leaves");3017 3018 leaveGame("Alice", game)3019 exists("after Alice leaves");30203021 leaveGame("Bob", game)30223023 destroyed();3024 });302530263027});302830293030describe("access security", function() {3031 before(getUserSessions);3032 3033 function checkAccess(desc, apiName) {3034 apiName = "/" + apiName;3035 it(desc + " (" + apiName + ")", function() {3036 return parseCall(null, apiName).then(3037 function(result) {3038 result.should.not.have.property("results");3039 result.should.have.property("code");3040 result.code.should.equal(119);3041 }3042 );3043 });3044 }30453046 describe("user access", function() {30473048 checkAccess("should not return list of users", "users");3049 checkAccess("should not return specific user", "users/etSAhagpLp");30503051 it("should return Alice", function() {3052 return parseCall("Alice", "/users/me").then(3053 function(result) {3054 result.should.have.property("objectId");3055 result.should.have.property("displayName");3056 result.displayName.should.equal("Ally");3057 }3058 );3059 });30603061 });30623063 function checkClassAccess(className) {3064 checkAccess("should not return list of " + className + "s", "classes/" + className);3065 }3066
...
CallModel.js
Source:CallModel.js
1export default class CallModel {2 // #parseRoom // storing the parseUser object as a private field (might need to use it)3 constructor(parseCall) {4 this.id = parseCall.id;5 this.title = parseCall.get("title");6 this.urgentLevel = parseCall.get("urgentLevel");7 this.description = parseCall.get("description");8 this.status = parseCall.get("status");9 this.notes = parseCall.get("notes");10 this.parseCall = parseCall;11 }12 async deleteCall() {13 const call = this.parseCall.destroy();14 return call;15 }16 async updateCall(notes, status) {17 console.log(notes, status, this.parseCall)18 const callInstance = this.parseCall;19 callInstance.set('notes', notes);20 callInstance.set('status', status);21 22 const parseHostel = await callInstance.save();23 // const call = this.parseCall.destroy();24 // return call;25 }...
parse-call.test.ts
Source:parse-call.test.ts
1import { StringParser, Types } from '../../src';2import { PossibleCalls } from '../../src/types';3describe('Testing StringParser.parseCall', () => {4 it('Testing a bid', () => {5 expect(StringParser.parseCall('1S')).toStrictEqual({6 call: { level: 1, suit: Types.Suit.Spade },7 });8 expect(StringParser.parseCall('7NT')).toStrictEqual({9 call: { level: 7, suit: Types.NoTrump },10 });11 });12 it('Testing pass', () => {13 expect(StringParser.parseCall('P')).toStrictEqual({14 call: PossibleCalls.Pass,15 });16 });17 it('Testing double', () => {18 expect(StringParser.parseCall('X')).toStrictEqual({19 call: PossibleCalls.Double,20 });21 });22 it('Testing redouble', () => {23 expect(StringParser.parseCall('xx')).toStrictEqual({24 call: PossibleCalls.Redouble,25 });26 });27 it('Testing throwing an error on an invalid call', () => {28 expect(() => StringParser.parseCall('t')).toThrowError();29 });...
Using AI Code Generation
1import { parseCall } from 'storybook-root';2import { parseCall } from 'storybook-root';3import { parseCall } from 'storybook-root';4import { parseCall } from 'storybook-root';5import { parseCall } from 'storybook-root';6import { parseCall } from 'storybook-root';7import { parseCall } from 'storybook-root';8import { parseCall } from 'storybook-root';9import { parseCall } from 'storybook-root';10import { parseCall } from 'storybook-root';11import { parseCall } from 'storybook-root';12import { parseCall } from 'storybook-root';13import { parseCall } from 'storybook-root';14import { parseCall } from 'storybook-root';15import { parseCall } from 'storybook-root';16import { parseCall } from 'storybook-root';17import { parseCall } from 'storybook-root';18import { parseCall } from 'storybook-root';19import { parseCall } from 'storybook-root';20import { parseCall } from 'storybook-root';
Using AI Code Generation
1import { parseCall } from 'storybook-root';2const parseCall = require('storybook-root').parseCall;3import { parseCall } from 'storybook-root/dist/lib';4const parseCall = require('storybook-root/dist/lib').parseCall;5import { parseCall } from 'storybook-root/dist/lib/index';6const parseCall = require('storybook-root/dist/lib/index').parseCall;7import { parseCall } from 'storybook-root/dist/lib/index.js';8const parseCall = require('storybook-root/dist/lib/index.js').parseCall;9import { parseCall } from 'storybook-root/dist/lib/index.cjs';10const parseCall = require('storybook-root/dist/lib/index.cjs').parseCall;11import { parseCall } from 'storybook-root/dist/lib/index.cjs.js';12const parseCall = require('storybook-root/dist/lib/index.cjs.js').parseCall;13import { parseCall } from 'storybook-root/dist/lib/index.mjs';14const parseCall = require('storybook-root/dist/lib/index.mjs').parseCall;15import { parseCall } from 'storybook-root/dist/lib/index.mjs.js';16const parseCall = require('storybook-root/dist/lib/index.mjs.js').parseCall;17import { parseCall } from 'storybook-root/dist/lib/index.mjs.js';18const parseCall = require('storybook-root/dist/lib/index.mjs.js').parseCall;19import { parseCall } from 'storybook-root/dist/lib
Using AI Code Generation
1import { parseCall } from 'storybook-root';2const { storiesOf, action } = parseCall('storiesOf', 'action');3storiesOf('MyComponent', module)4 .add('story', () => <MyComponent onClick={action('click')} />);5import { parseCall } from 'storybook-root';6const { storiesOf, action } = parseCall('storiesOf', 'action');7storiesOf('MyComponent', module)8 .add('story', () => <MyComponent onClick={action('click')} />);9parseCall(methodName: string, ...args: string[]): any10import { parseCall } from 'storybook-root';11const { storiesOf, action } = parseCall('storiesOf', 'action');12storiesOf('MyComponent', module)13 .add('story', () => <MyComponent onClick={action('click')} />);14import { parseCall } from 'storybook-root';15const { myMethod } = parseCall('myMethod');16myMethod('MyComponent', module)17 .add('story', () => <MyComponent />);18import { parseCall } from 'storybook-root';19const { storiesOf, action, myMethod } = parseCall('storiesOf', 'action', 'myMethod');20storiesOf('MyComponent', module)21 .add('story', () => <MyComponent onClick={action('click')} />);22myMethod('MyComponent', module)23 .add('story', () => <MyComponent />);
Using AI Code Generation
1import { parseCall } from 'storybook-root';2const { component, args, options } = parseCall(3 { label: 'Hello' },4 { argTypes: { label: { control: 'text' } } }5);6import { Button } from 'storybook-root';7export default {8 argTypes: {9 label: {10 },11 },12};13const Template = (args) => ({14 components: { Button },15 setup() {16 return { args };17 },18});19export const Primary = Template.bind({});20Primary.args = {21};22import { Button } from 'storybook-root';23export default {24 argTypes: {25 label: {26 },27 },28};29const Template = (args) => ({30 components: { Button },31 setup() {32 return { args };33 },34});35export const Primary = Template.bind({});36Primary.args = {37};38import { Button } from 'storybook-root';39export default {40 argTypes: {41 label: {42 },43 },44};45const Template = (args) => ({46 components: { Button },47 setup() {48 return { args };49 },50});51export const Primary = Template.bind({});52Primary.args = {53};54import { Button } from 'storybook-root';55export default {56 argTypes: {57 label: {58 },59 },60};61const Template = (args
Using AI Code Generation
1const root = require('storybook-root');2const { parseCall } = root;3const call = parseCall('test', { a: 'b' });4console.log(call);5const root = require('storybook-root');6const { parseCall } = root;7const call = parseCall('test', { a: 'b' });8console.log(call);9const root = require('storybook-root');10const { parseCall } = root;11const call = parseCall('test', { a: 'b' });12console.log(call);13const root = require('storybook-root');14const { parseCall } = root;15const call = parseCall('test', { a: 'b' });16console.log(call);17const root = require('storybook-root');18const { parseCall } = root;19const call = parseCall('test', { a: 'b' });20console.log(call);21const root = require('storybook-root');22const { parseCall } = root;23const call = parseCall('test', { a: 'b' });24console.log(call);25const root = require('storybook-root');26const { parseCall } = root;27const call = parseCall('test', { a: 'b' });28console.log(call);29const root = require('storybook-root');30const { parseCall } = root;31const call = parseCall('test', { a: 'b' });32console.log(call);33const root = require('storybook-root');34const { parseCall } = root;35const call = parseCall('test', { a: 'b' });36console.log(call);37const root = require('storybook-root');38const { parseCall }
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!