UNPKG

modaq

Version:

Quiz Bowl Reader using TypeScript, React, and MobX

914 lines 65.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const chai_1 = require("chai"); const GameFormats = __importStar(require("src/state/GameFormats")); const Sheets = __importStar(require("src/sheets/Sheets")); require("src/sheets/ISheetsApi"); const AppState_1 = require("src/state/AppState"); const IPendingNewGame_1 = require("src/state/IPendingNewGame"); const SheetState_1 = require("src/state/SheetState"); require("src/IStatus"); const TeamState_1 = require("src/state/TeamState"); const PacketState_1 = require("src/state/PacketState"); require("src/state/Cycle"); require("src/state/IGameFormat"); const defaultMockSheetsApi = { batchClear: () => Promise.resolve({ isError: false, status: "" }), batchGet: () => Promise.resolve({ success: true, valueRanges: [], }), batchUpdate: () => Promise.resolve({ isError: false, status: "" }), initializeIfNeeded: () => Promise.resolve(), get: () => Promise.resolve({ success: true, valueRange: { values: [], }, }), }; function createMockApi(mocks) { const sheetsApi = Object.assign(Object.assign({}, defaultMockSheetsApi), mocks); return sheetsApi; } function createAppStateForExport(sheetType = SheetState_1.SheetType.Lifsheets) { const appState = new AppState_1.AppState(); appState.game.addNewPlayers([new TeamState_1.Player("Alice", "Alpha", true), new TeamState_1.Player("Bob", "Beta", true)]); const packet = new PacketState_1.PacketState(); packet.setTossups([new PacketState_1.Tossup("This tossup has five words.", "A")]); packet.setBonuses([ new PacketState_1.Bonus("Leadin", [ { question: "Part 1", answer: "A1", value: 10 }, { question: "Part 2", answer: "A2", value: 10 }, { question: "Part 3", answer: "A3", value: 10 }, ]), ]); appState.game.loadPacket(packet); appState.uiState.sheetsState.setSheetId("1"); appState.uiState.sheetsState.setSheetType(sheetType); return appState; } function createAppStateForRosters(sheetType = SheetState_1.SheetType.Lifsheets, pendingGameType = IPendingNewGame_1.PendingGameType.TJSheets) { const appState = new AppState_1.AppState(); appState.uiState.createPendingNewGame(); appState.uiState.setPendingNewGameType(pendingGameType); appState.uiState.sheetsState.setSheetId("1"); appState.uiState.sheetsState.setSheetType(sheetType); return appState; } function findPlayerOnTeam(appState, teamName) { const player = appState.game.players.find((player) => player.teamName === teamName); if (player == undefined) { // Use an if since we want to coerce away the undefined type chai_1.assert.fail("No players on team Alpha"); } return player; } function verifyExportToSheetsError(appState, sheetsApi, errorMessage) { var _a, _b, _c; return __awaiter(this, void 0, void 0, function* () { yield Sheets.exportToSheet(appState, sheetsApi); chai_1.expect(appState.uiState.sheetsState).to.exist; chai_1.expect((_a = appState.uiState.sheetsState.exportStatus) === null || _a === void 0 ? void 0 : _a.isError).to.exist; chai_1.expect((_b = appState.uiState.sheetsState.exportStatus) === null || _b === void 0 ? void 0 : _b.isError).to.be.true; chai_1.expect((_c = appState.uiState.sheetsState.exportStatus) === null || _c === void 0 ? void 0 : _c.status).to.equal(errorMessage); chai_1.expect(appState.uiState.sheetsState.exportState).to.equal(SheetState_1.ExportState.Error); }); } function verifyExportToSheetSuccess(appState, verifyCells) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { let ranges = []; const mockSheetsApi = createMockApi({ batchUpdate: (_uiState, valueRanges) => { ranges = valueRanges; return Promise.resolve({ isError: false, status: "", }); }, }); // We use a flow here since it greatly simplifies using a reactive context with asynchronous code. // See https://www.mobxjs.com/best/actions.html and https://mobx.js.org/actions.html#using-flow-instead-of-async--await- yield Sheets.exportToSheet(appState, mockSheetsApi); chai_1.expect(appState.uiState.sheetsState).to.exist; chai_1.expect((_a = appState.uiState.sheetsState.exportStatus) === null || _a === void 0 ? void 0 : _a.isError).to.exist; chai_1.expect((_b = appState.uiState.sheetsState.exportStatus) === null || _b === void 0 ? void 0 : _b.isError).to.be.false; chai_1.expect(appState.uiState.sheetsState.exportState).to.equal(SheetState_1.ExportState.Success); verifyCells(ranges); }); } function verifyLoadRostersError(appState, sheetsApi, errorMessage) { var _a, _b, _c; return __awaiter(this, void 0, void 0, function* () { yield Sheets.loadRosters(appState, sheetsApi); chai_1.expect(appState.uiState.sheetsState).to.exist; chai_1.expect((_a = appState.uiState.sheetsState.rosterLoadStatus) === null || _a === void 0 ? void 0 : _a.isError).to.exist; chai_1.expect((_b = appState.uiState.sheetsState.rosterLoadStatus) === null || _b === void 0 ? void 0 : _b.isError).to.be.true; chai_1.expect((_c = appState.uiState.sheetsState.rosterLoadStatus) === null || _c === void 0 ? void 0 : _c.status).to.equal(errorMessage); chai_1.expect(appState.uiState.sheetsState.rosterLoadState).to.equal(SheetState_1.LoadingState.Error); }); } function verifyCell(ranges, cellRange, value) { const cell = ranges.find((range) => range.range === `'Round 1'!${cellRange}`); if (cell == undefined) { chai_1.assert.fail(`Couldn't find update for cell at ${cellRange}. Ranges: ${JSON.stringify(ranges)}`); } else if (cell.values == undefined) { chai_1.assert.fail(`No values in the update. Ranges: ${JSON.stringify(ranges)}`); } chai_1.expect(cell.values.length).to.equal(1); chai_1.expect(cell.values[0].length).to.equal(1); chai_1.expect(cell.values[0][0]).to.equal(value); } function verifyNoCell(ranges, cellRange) { const cell = ranges.find((range) => range.range === `'Round 1'!${cellRange}`); chai_1.expect(cell).to.be.undefined; } function verifyUCSDBonusCells(ranges, cellRange, values) { const cell = ranges.find((range) => range.range === `'Round 1'!${cellRange}`); if (cell == undefined) { chai_1.assert.fail(`Couldn't find update for cell at I4:K4. Ranges: ${JSON.stringify(ranges)}`); } else if (cell.values == undefined) { chai_1.assert.fail(`No values in the update. Ranges: ${JSON.stringify(ranges)}`); } chai_1.expect(cell.values.length).to.equal(1); chai_1.expect(cell.values[0].length).to.equal(values.length); chai_1.expect(cell.values[0]).to.deep.equal(values); } describe("SheetsTests", () => { describe("exportToSheet", () => { // TODO: Should we have a test for when a player is subbed in on the second question? Conflicts with "Out"/"In", // but I don't know how Lifsheets tries to account for that // TODO: Any tests with AddPlayer? Doesn't make sense with Lifsheets, where the roster exists elsewhere... const firstTeamNegTest = (sheetType, verifyCells) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const player = findPlayerOnTeam(appState, "Alpha"); const position = 1; appState.game.cycles[0].addWrongBuzz({ player, position, points: -5, isLastWord: false, }, 0, appState.game.gameFormat); yield verifyExportToSheetSuccess(appState, (ranges) => verifyCells(ranges, position)); }); it("First team neg written to sheet (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield firstTeamNegTest(SheetState_1.SheetType.Lifsheets, (ranges, position) => { verifyCell(ranges, "B8", -5); verifyCell(ranges, "AJ8", position); }); })); it("First team neg written to sheet (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield firstTeamNegTest(SheetState_1.SheetType.TJSheets, (ranges) => verifyCell(ranges, "C4", -5)); })); it("First team neg written to sheet (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield firstTeamNegTest(SheetState_1.SheetType.UCSDSheets, (ranges) => verifyCell(ranges, "C4", -5)); })); const secondTeamNegTest = (sheetType, verifyCells) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const player = findPlayerOnTeam(appState, "Beta"); const position = 1; appState.game.cycles[0].addWrongBuzz({ player, position, points: -5, isLastWord: false, }, 0, appState.game.gameFormat); yield verifyExportToSheetSuccess(appState, (ranges) => verifyCells(ranges, position)); }); it("Second team neg written to sheet (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield secondTeamNegTest(SheetState_1.SheetType.Lifsheets, (ranges, position) => { verifyCell(ranges, "R8", -5); verifyCell(ranges, "AJ8", position); }); })); it("Second team neg written to sheet (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield secondTeamNegTest(SheetState_1.SheetType.TJSheets, (ranges) => verifyCell(ranges, "M4", -5)); })); it("Second team neg written to sheet (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield secondTeamNegTest(SheetState_1.SheetType.UCSDSheets, (ranges) => verifyCell(ranges, "O4", -5)); })); const nonNegNotWrittenTest = (sheetType, verifyCells) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const player = findPlayerOnTeam(appState, "Alpha"); const position = 1; appState.game.cycles[0].addWrongBuzz({ player, position, points: -5, isLastWord: false, }, 0, appState.game.gameFormat); const secondPlayer = findPlayerOnTeam(appState, "Beta"); appState.game.cycles[0].addWrongBuzz({ player: secondPlayer, position, points: 0, isLastWord: false, }, 0, appState.game.gameFormat); yield verifyExportToSheetSuccess(appState, (ranges) => verifyCells(ranges, position)); }); it("First team neg written, second team no penalty not written (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield nonNegNotWrittenTest(SheetState_1.SheetType.Lifsheets, (ranges, position) => { verifyCell(ranges, "B8", -5); verifyCell(ranges, "AJ8", position); verifyNoCell(ranges, "R8"); verifyNoCell(ranges, "AK8"); }); })); it("First team neg written, second team no penalty not written (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield nonNegNotWrittenTest(SheetState_1.SheetType.TJSheets, (ranges) => { verifyCell(ranges, "C4", -5); verifyNoCell(ranges, "M4"); }); })); it("First team neg written, second team no penalty not written (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield nonNegNotWrittenTest(SheetState_1.SheetType.UCSDSheets, (ranges) => { verifyCell(ranges, "C4", -5); verifyNoCell(ranges, "O4"); }); })); const firstCorrectBuzzTest = (sheetType, verifyCells) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const player = findPlayerOnTeam(appState, "Alpha"); const position = 2; const cycle = appState.game.cycles[0]; cycle.addCorrectBuzz({ player, position, points: 10, isLastWord: false, }, 0, appState.game.gameFormat, 0, 3); cycle.setBonusPartAnswer(0, player.teamName, 10); cycle.setBonusPartAnswer(1, player.teamName, 10); cycle.setBonusPartAnswer(2, player.teamName, 0); yield verifyExportToSheetSuccess(appState, (ranges) => verifyCells(ranges, position)); }); it("First team correct buzz written to sheet (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield firstCorrectBuzzTest(SheetState_1.SheetType.Lifsheets, (ranges, position) => { verifyCell(ranges, "B8", 10); verifyCell(ranges, "AJ8", position); // Verify bonus verifyCell(ranges, "H8", "110"); }); })); it("First team correct buzz written to sheet (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield firstCorrectBuzzTest(SheetState_1.SheetType.TJSheets, (ranges) => { verifyCell(ranges, "C4", 10); // Verify bonus verifyCell(ranges, "I4", 20); }); })); it("First team correct buzz written to sheet (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield firstCorrectBuzzTest(SheetState_1.SheetType.UCSDSheets, (ranges) => { verifyCell(ranges, "C4", 10); // Verify bonus verifyUCSDBonusCells(ranges, "I4:K4", [true, true, false]); }); })); const secondCorrectBuzzTest = (sheetType, verifyCells) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const player = findPlayerOnTeam(appState, "Beta"); const position = 2; const cycle = appState.game.cycles[0]; cycle.addCorrectBuzz({ player, position, points: 10, isLastWord: false, }, 0, appState.game.gameFormat, 0, 3); cycle.setBonusPartAnswer(0, player.teamName, 0); cycle.setBonusPartAnswer(1, player.teamName, 0); cycle.setBonusPartAnswer(2, player.teamName, 10); yield verifyExportToSheetSuccess(appState, (ranges) => verifyCells(ranges, position)); }); it("Second team correct buzz written to sheet (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield secondCorrectBuzzTest(SheetState_1.SheetType.Lifsheets, (ranges, position) => { verifyCell(ranges, "R8", 10); verifyCell(ranges, "AJ8", position); // Verify bonus verifyCell(ranges, "X8", "001"); }); })); it("Second team correct buzz written to sheet (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield secondCorrectBuzzTest(SheetState_1.SheetType.TJSheets, (ranges) => { verifyCell(ranges, "M4", 10); // Verify bonus verifyCell(ranges, "S4", 10); }); })); it("Second team correct buzz written to sheet (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield secondCorrectBuzzTest(SheetState_1.SheetType.UCSDSheets, (ranges) => { verifyCell(ranges, "O4", 10); // Verify bonus verifyUCSDBonusCells(ranges, "U4:W4", [false, false, true]); }); })); const playerPowersTest = (sheetType, verifyCells) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const packet = new PacketState_1.PacketState(); packet.setTossups([new PacketState_1.Tossup("This tossup has (*) five words.", "A")]); packet.setBonuses([ new PacketState_1.Bonus("Leadin", [ { question: "Part 1", answer: "A1", value: 10 }, { question: "Part 2", answer: "A2", value: 10 }, { question: "Part 3", answer: "A3", value: 10 }, ]), ]); appState.game.loadPacket(packet); appState.game.setGameFormat(GameFormats.StandardPowersMACFGameFormat); const player = findPlayerOnTeam(appState, "Alpha"); const position = 2; const cycle = appState.game.cycles[0]; cycle.addCorrectBuzz({ player, position, points: 15, isLastWord: false, }, 0, appState.game.gameFormat, 0, 3); cycle.setBonusPartAnswer(0, player.teamName, 10); cycle.setBonusPartAnswer(1, player.teamName, 10); cycle.setBonusPartAnswer(2, player.teamName, 0); yield verifyExportToSheetSuccess(appState, (ranges) => verifyCells(ranges, position)); }); it("First team player powers written to sheet (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield playerPowersTest(SheetState_1.SheetType.Lifsheets, (ranges, position) => { verifyCell(ranges, "B8", 15); verifyCell(ranges, "AJ8", position); // Verify bonus verifyCell(ranges, "H8", "110"); }); })); it("First team player powers written to sheet (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield playerPowersTest(SheetState_1.SheetType.TJSheets, (ranges) => { verifyCell(ranges, "C4", 15); // Verify bonus verifyCell(ranges, "I4", 20); }); })); it("First team player powers written to sheet (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield playerPowersTest(SheetState_1.SheetType.UCSDSheets, (ranges) => { verifyCell(ranges, "C4", 15); // Verify bonus verifyUCSDBonusCells(ranges, "I4:K4", [true, true, false]); }); })); const twoBuzzesInSameCycleTest = (sheetType, verifyCells) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const firstTeamPlayer = findPlayerOnTeam(appState, "Alpha"); const secondTeamPlayer = findPlayerOnTeam(appState, "Beta"); const negPosition = 2; const correctPosition = 4; const cycle = appState.game.cycles[0]; cycle.addWrongBuzz({ player: secondTeamPlayer, position: negPosition, points: -5, isLastWord: false, }, 0, appState.game.gameFormat); cycle.addCorrectBuzz({ player: firstTeamPlayer, position: correctPosition, points: 10, isLastWord: true, }, 0, appState.game.gameFormat, 0, 3); cycle.setBonusPartAnswer(0, firstTeamPlayer.teamName, 10); cycle.setBonusPartAnswer(1, firstTeamPlayer.teamName, 10); cycle.setBonusPartAnswer(2, firstTeamPlayer.teamName, 0); yield verifyExportToSheetSuccess(appState, (ranges) => verifyCells(ranges, negPosition, correctPosition)); }); it("Two buzzes in same cycle (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield twoBuzzesInSameCycleTest(SheetState_1.SheetType.Lifsheets, (ranges, negPosition, correctPosition) => { verifyCell(ranges, "R8", -5); verifyCell(ranges, "B8", 10); verifyCell(ranges, "AJ8", negPosition); verifyCell(ranges, "AK8", correctPosition); // Verify bonus verifyCell(ranges, "H8", "110"); }); })); it("Two buzzes in same cycle (TJ Sheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield twoBuzzesInSameCycleTest(SheetState_1.SheetType.TJSheets, (ranges) => { verifyCell(ranges, "M4", -5); verifyCell(ranges, "C4", 10); // Verify bonus verifyCell(ranges, "I4", 20); }); })); it("Two buzzes in same cycle (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield twoBuzzesInSameCycleTest(SheetState_1.SheetType.UCSDSheets, (ranges) => { verifyCell(ranges, "O4", -5); verifyCell(ranges, "C4", 10); // Verify bonus verifyUCSDBonusCells(ranges, "I4:K4", [true, true, false]); }); })); it("First team tossup protest written to sheet", () => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(SheetState_1.SheetType.Lifsheets); const player = findPlayerOnTeam(appState, "Alpha"); const position = 1; appState.game.cycles[0].addWrongBuzz({ player, position, points: -5, isLastWord: false, }, 0, appState.game.gameFormat); const reason = "I was right"; const answer = "That answer"; appState.game.cycles[0].addTossupProtest("Alpha", 0, position, answer, reason); yield verifyExportToSheetSuccess(appState, (ranges) => { verifyCell(ranges, "B8", -5); verifyCell(ranges, "AF8", reason); }); })); it("Second team tossup protest written to sheet", () => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(SheetState_1.SheetType.Lifsheets); const player = findPlayerOnTeam(appState, "Beta"); const position = 1; appState.game.cycles[0].addWrongBuzz({ player, position, points: -5, isLastWord: false, }, 0, appState.game.gameFormat); const reason = "I was surely right"; const answer = "The answer"; appState.game.cycles[0].addTossupProtest("Beta", 0, position, answer, reason); yield verifyExportToSheetSuccess(appState, (ranges) => { verifyCell(ranges, "R8", -5); verifyCell(ranges, "AG8", reason); }); })); it("First team bonus protest written to sheet", () => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(); const player = findPlayerOnTeam(appState, "Alpha"); const position = 1; const cycle = appState.game.cycles[0]; cycle.addCorrectBuzz({ player, position, points: 10, isLastWord: false, }, 0, appState.game.gameFormat, 0, 3); cycle.setBonusPartAnswer(0, player.teamName, 0); cycle.setBonusPartAnswer(1, player.teamName, 10); cycle.setBonusPartAnswer(2, player.teamName, 10); const reason = "I was right"; const answer = "My answer"; cycle.addBonusProtest(0, 0, answer, reason, "Alpha"); yield verifyExportToSheetSuccess(appState, (ranges) => { verifyCell(ranges, "B8", 10); verifyCell(ranges, "H8", "011"); verifyCell(ranges, "AH8", reason); }); })); it("Second team bonus protest written to sheet", () => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(SheetState_1.SheetType.Lifsheets); const player = findPlayerOnTeam(appState, "Beta"); const position = 2; const cycle = appState.game.cycles[0]; cycle.addCorrectBuzz({ player, position, points: 10, isLastWord: false, }, 0, appState.game.gameFormat, 0, 3); cycle.setBonusPartAnswer(0, player.teamName, 10); cycle.setBonusPartAnswer(1, player.teamName, 0); cycle.setBonusPartAnswer(2, player.teamName, 10); const reason = "I was surely right"; const answer = "My certain answer"; cycle.addBonusProtest(0, 1, answer, reason, "Beta"); yield verifyExportToSheetSuccess(appState, (ranges) => { verifyCell(ranges, "R8", 10); verifyCell(ranges, "X8", "101"); verifyCell(ranges, "AH8", reason); }); })); it("Multiple bonus protests written to sheet", () => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(SheetState_1.SheetType.Lifsheets); const player = findPlayerOnTeam(appState, "Alpha"); const position = 1; const cycle = appState.game.cycles[0]; cycle.addCorrectBuzz({ player, position, points: 10, isLastWord: false, }, 0, appState.game.gameFormat, 0, 3); cycle.setBonusPartAnswer(0, player.teamName, 0); cycle.setBonusPartAnswer(1, player.teamName, 10); cycle.setBonusPartAnswer(2, player.teamName, 0); const firstReason = "I was right"; const firstAnswer = "Some answer"; const secondReason = "That was also right"; const secondAnswer = "Another answer"; cycle.addBonusProtest(0, 0, firstAnswer, firstReason, "Alpha"); cycle.addBonusProtest(0, 2, secondAnswer, secondReason, "Alpha"); yield verifyExportToSheetSuccess(appState, (ranges) => { verifyCell(ranges, "B8", 10); verifyCell(ranges, "H8", "010"); verifyCell(ranges, "AH8", [firstReason, secondReason].join("\n")); }); })); it("First team bouncebacks written to sheet (TJ Sheets)", () => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(SheetState_1.SheetType.TJSheets); appState.game.setGameFormat(Object.assign(Object.assign({}, appState.game.gameFormat), { bonusesBounceBack: true })); const player = findPlayerOnTeam(appState, "Beta"); const position = 1; const cycle = appState.game.cycles[0]; cycle.addCorrectBuzz({ player, position, points: 10, isLastWord: false, }, 0, appState.game.gameFormat, 0, 3); cycle.setBonusPartAnswer(0, player.teamName, 10); cycle.setBonusPartAnswer(1, "Alpha", 10); cycle.setBonusPartAnswer(2, "Alpha", 10); yield verifyExportToSheetSuccess(appState, (ranges) => { verifyCell(ranges, "M4", 10); verifyCell(ranges, "S4", 10); verifyCell(ranges, "J4", 20); }); })); it("Second team bouncebacks written to sheet (TJ Sheets)", () => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(SheetState_1.SheetType.TJSheets); appState.game.setGameFormat(Object.assign(Object.assign({}, appState.game.gameFormat), { bonusesBounceBack: true })); const player = findPlayerOnTeam(appState, "Alpha"); const position = 1; const cycle = appState.game.cycles[0]; cycle.addCorrectBuzz({ player, position, points: 10, isLastWord: false, }, 0, appState.game.gameFormat, 0, 3); cycle.setBonusPartAnswer(0, player.teamName, 10); cycle.setBonusPartAnswer(1, player.teamName, 10); cycle.setBonusPartAnswer(2, "Beta", 10); yield verifyExportToSheetSuccess(appState, (ranges) => { verifyCell(ranges, "C4", 10); verifyCell(ranges, "I4", 20); verifyCell(ranges, "T4", 10); }); })); const firstTeamSubsTest = (sheetType, verifyCells) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const starter = findPlayerOnTeam(appState, "Alpha"); const sub = new TeamState_1.Player("Adam", "Alpha", /* isStarter */ false); appState.game.addNewPlayer(sub); const packet = new PacketState_1.PacketState(); const tossups = []; for (let i = 0; i < 4; i++) { tossups.push(new PacketState_1.Tossup(`TU${i}`, `Answer ${i}`)); } packet.setTossups(tossups); appState.game.loadPacket(packet); // Swap in the 3rd phase appState.game.cycles[2].addSwapSubstitution(sub, starter); yield verifyExportToSheetSuccess(appState, verifyCells); }); it("First team subs (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield firstTeamSubsTest(SheetState_1.SheetType.Lifsheets, (ranges) => { // All subs should start with "Out" verifyCell(ranges, "C8", "Out"); // The subbed out player should have Out in the cycle they were subbed out, and the subbed in player // should have In in the previous cycle verifyCell(ranges, "B10", "Out"); verifyCell(ranges, "C9", "In"); }); })); it("First team subs (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield firstTeamSubsTest(SheetState_1.SheetType.TJSheets, (ranges) => { // All subs should start with "Out" verifyCell(ranges, "D3", "Adam"); // Subbed on the 3rd question verifyCell(ranges, "D28", 3); verifyCell(ranges, "C29", 3); }); })); it("First team subs (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield firstTeamSubsTest(SheetState_1.SheetType.UCSDSheets, (ranges) => { // There's no explicit substitution, just a count of how many tossups have been heard verifyCell(ranges, "C32", 2); verifyCell(ranges, "D32", 2); verifyCell(ranges, "O32", 4); }); })); const secondTeamSubsTest = (sheetType, verifyCells) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const starter = findPlayerOnTeam(appState, "Beta"); const sub = new TeamState_1.Player("Barbara", "Beta", /* isStarter */ false); appState.game.addNewPlayer(sub); const packet = new PacketState_1.PacketState(); const tossups = []; for (let i = 0; i < 4; i++) { tossups.push(new PacketState_1.Tossup(`TU${i}`, `Answer ${i}`)); } packet.setTossups(tossups); appState.game.loadPacket(packet); // Swap in the 4th phase appState.game.cycles[3].addSwapSubstitution(sub, starter); yield verifyExportToSheetSuccess(appState, verifyCells); }); it("Second team subs (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield secondTeamSubsTest(SheetState_1.SheetType.Lifsheets, (ranges) => { // All subs should start with "Out" verifyCell(ranges, "S8", "Out"); // The subbed out player should have Out in the cycle they were subbed out, and the subbed in player // should have In in the previous cycle verifyCell(ranges, "R11", "Out"); verifyCell(ranges, "S10", "In"); }); })); it("Second team subs (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield secondTeamSubsTest(SheetState_1.SheetType.TJSheets, (ranges) => { // All subs should start with "Out" verifyCell(ranges, "N3", "Barbara"); // Subbed on the 3rd question verifyCell(ranges, "N28", 4); verifyCell(ranges, "M29", 4); }); })); it("Second team subs (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield secondTeamSubsTest(SheetState_1.SheetType.UCSDSheets, (ranges) => { // There's no explicit substitution, just a count of how many tossups have been heard verifyCell(ranges, "O32", 3); verifyCell(ranges, "P32", 1); verifyCell(ranges, "C32", 4); }); })); const deadTossupTest = (sheetType, verifyCells) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const player = findPlayerOnTeam(appState, "Beta"); appState.game.cycles[0].addWrongBuzz({ player, points: -5, position: 1, isLastWord: false, }, 0, appState.game.gameFormat); yield verifyExportToSheetSuccess(appState, verifyCells); }); it("Dead tossup (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield deadTossupTest(SheetState_1.SheetType.Lifsheets, (ranges) => { verifyCell(ranges, "Q8", 1); }); })); it("Dead tossup (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield deadTossupTest(SheetState_1.SheetType.TJSheets, (ranges) => { verifyCell(ranges, "I4", "DT"); }); })); it("batchClear API failure", () => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(); const status = "Couldn't connect to Sheets"; const mockSheetsApi = createMockApi({ batchClear: () => Promise.resolve({ isError: true, status, }), }); yield verifyExportToSheetsError(appState, mockSheetsApi, `Error from Sheets API clearing the values. Error: ${status}`); })); it("batchUpdate API failure", () => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(); const status = "Couldn't connect to Sheets"; const mockSheetsApi = createMockApi({ batchUpdate: () => Promise.resolve({ isError: true, status, }), }); yield verifyExportToSheetsError(appState, mockSheetsApi, `Error from Sheets API writing the values. Error: ${status}`); })); it("Missing SheetsId", () => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(); appState.uiState.resetSheetsId(); yield verifyExportToSheetsError(appState, defaultMockSheetsApi, "Export requires a sheet ID"); })); const moreThanTwoTeamsTest = (sheetType) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); appState.game.addNewPlayer(new TeamState_1.Player("Gail", "Gamma", true)); yield verifyExportToSheetsError(appState, defaultMockSheetsApi, "Export not allowed with more than two teams"); }); it("More than two teams (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield moreThanTwoTeamsTest(SheetState_1.SheetType.Lifsheets); })); it("More than two teams (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield moreThanTwoTeamsTest(SheetState_1.SheetType.TJSheets); })); it("More than two teams (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield moreThanTwoTeamsTest(SheetState_1.SheetType.UCSDSheets); })); const sixPlayersOnTeamSucceedsTest = (sheetType) => __awaiter(void 0, void 0, void 0, function* () { var _a, _b; const appState = createAppStateForExport(sheetType); const alphaPlayersCount = appState.game.players.filter((player) => player.teamName === "Alpha") .length; for (let i = 0; i < 6 - alphaPlayersCount; i++) { appState.game.addNewPlayer(new TeamState_1.Player(`New${i}`, "Alpha", false)); } yield Sheets.exportToSheet(appState, defaultMockSheetsApi); chai_1.expect(appState.uiState.sheetsState).to.exist; chai_1.expect((_a = appState.uiState.sheetsState.exportStatus) === null || _a === void 0 ? void 0 : _a.isError).to.exist; chai_1.expect((_b = appState.uiState.sheetsState.exportStatus) === null || _b === void 0 ? void 0 : _b.isError).to.be.false; chai_1.expect(appState.uiState.sheetsState.exportState).to.equal(SheetState_1.ExportState.Success); }); it("Six players on a team succeeds (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield sixPlayersOnTeamSucceedsTest(SheetState_1.SheetType.Lifsheets); })); it("Six players on a team succeeds (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield sixPlayersOnTeamSucceedsTest(SheetState_1.SheetType.TJSheets); })); it("Six players on a team succeeds (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield sixPlayersOnTeamSucceedsTest(SheetState_1.SheetType.UCSDSheets); })); const sevenPlayersOnTeamFailsTest = (sheetType) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const alphaPlayersCount = appState.game.players.filter((player) => player.teamName === "Alpha") .length; for (let i = 0; i < 7 - alphaPlayersCount; i++) { appState.game.addNewPlayer(new TeamState_1.Player(`New${i}`, "Alpha", false)); } yield verifyExportToSheetsError(appState, defaultMockSheetsApi, "Export not allowed with more than six players per a team"); }); it("Seven players on a team fails (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield sevenPlayersOnTeamFailsTest(SheetState_1.SheetType.Lifsheets); })); it("Seven players on a team fails (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield sevenPlayersOnTeamFailsTest(SheetState_1.SheetType.TJSheets); })); it("Seven players on a team fails (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield sevenPlayersOnTeamFailsTest(SheetState_1.SheetType.UCSDSheets); })); const tossupLimitCycleSucceedsTest = (sheetType, tossupsScored, verifyCells) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const packet = new PacketState_1.PacketState(); const tossups = []; for (let i = 0; i < tossupsScored; i++) { tossups.push(new PacketState_1.Tossup(`TU${i}`, `Answer ${i}`)); } packet.setTossups(tossups); appState.game.loadPacket(packet); const player = findPlayerOnTeam(appState, "Alpha"); const position = 3; appState.game.cycles[tossupsScored - 1].addCorrectBuzz({ player, position, points: 10, isLastWord: false, }, 20, appState.game.gameFormat, 0, 3); yield verifyExportToSheetSuccess(appState, (ranges) => verifyCells(ranges, position)); }); it("Twenty-one cycles succeeds (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield tossupLimitCycleSucceedsTest(SheetState_1.SheetType.Lifsheets, 21, (ranges, position) => { // Verify that we do write to the last cell (the tiebreaker one) verifyCell(ranges, "B28", 10); verifyCell(ranges, "AJ28", position); }); })); it("Twenty-four cycles succeeds (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield tossupLimitCycleSucceedsTest(SheetState_1.SheetType.TJSheets, 24, (ranges) => { // Verify that we do write to the last cell (the tiebreaker one) verifyCell(ranges, "C27", 10); }); })); it("Twenty-eight cycles succeeds (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield tossupLimitCycleSucceedsTest(SheetState_1.SheetType.UCSDSheets, 28, (ranges) => { // Verify that we do write to the last cell (the tiebreaker one) verifyCell(ranges, "C31", 10); }); })); const pastTossupLimitCycleFailsTest = (sheetType, tossupsCount) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const packet = new PacketState_1.PacketState(); const tossups = []; for (let i = 0; i < tossupsCount; i++) { tossups.push(new PacketState_1.Tossup(`TU${i}`, `Answer ${i}`)); } packet.setTossups(tossups); appState.game.loadPacket(packet); yield verifyExportToSheetsError(appState, defaultMockSheetsApi, `Export not allowed with more than ${tossupsCount - 1} rounds (not enough rows)`); }); it("Twenty-two cycles fails (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield pastTossupLimitCycleFailsTest(SheetState_1.SheetType.Lifsheets, 22); })); it("Twenty-five cycles fails (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield pastTossupLimitCycleFailsTest(SheetState_1.SheetType.TJSheets, 25); })); it("Twenty-nine cycles fails (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield pastTossupLimitCycleFailsTest(SheetState_1.SheetType.UCSDSheets, 29); })); const onlyPlayedCyclesWrittenTest = (sheetType, verifyCells) => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(sheetType); const gameFormat = Object.assign(Object.assign({}, GameFormats.UndefinedGameFormat), { regulationTossupCount: 1 }); appState.game.setGameFormat(gameFormat); const packet = new PacketState_1.PacketState(); const tossups = []; for (let i = 0; i < 10; i++) { tossups.push(new PacketState_1.Tossup(`TU${i}`, `Answer ${i}`)); } packet.setTossups(tossups); appState.game.loadPacket(packet); const player = findPlayerOnTeam(appState, "Alpha"); const position = 3; appState.game.cycles[0].addCorrectBuzz({ player, position, points: 10, isLastWord: false, }, 0, appState.game.gameFormat, 0, 3); // Make sure the second buzz isn't recorded appState.game.cycles[1].addWrongBuzz({ player, position, points: -5, isLastWord: false, }, 1, gameFormat); yield verifyExportToSheetSuccess(appState, (ranges) => verifyCells(ranges, position)); }); it("Only played cycles written (Lifsheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield onlyPlayedCyclesWrittenTest(SheetState_1.SheetType.Lifsheets, (ranges, position) => { verifyCell(ranges, "B8", 10); verifyCell(ranges, "AJ8", position); chai_1.expect(ranges.find((range) => range.range != undefined && range.range.indexOf("B9") >= 0)).to.be .undefined; }); })); it("Only played cycles written (TJSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield onlyPlayedCyclesWrittenTest(SheetState_1.SheetType.TJSheets, (ranges) => { verifyCell(ranges, "C4", 10); chai_1.expect(ranges.find((range) => range.range != undefined && range.range.indexOf("C5") >= 0)).to.be .undefined; }); })); it("Only played cycles written (UCSDSheets)", () => __awaiter(void 0, void 0, void 0, function* () { yield onlyPlayedCyclesWrittenTest(SheetState_1.SheetType.UCSDSheets, (ranges) => { verifyCell(ranges, "C4", 10); chai_1.expect(ranges.find((range) => range.range != undefined && range.range.indexOf("C5") >= 0)).to.be .undefined; }); })); it("Filled in sheet gets prompted", () => __awaiter(void 0, void 0, void 0, function* () { const appState = createAppStateForExport(); let updateCount = 0; const mockSheetsApi = createMockApi({ batchGet: () => Promise.resolve({ success: true, valueRanges: [ { values: [["A"]], }, ], }), batchUpdate: () => { updateCount++; return Promise.resolve({ isError: false, status: "" }); }, }); yield Sheets.exportToSheet(appState, mockSheetsApi); chai_1.expect(appState.uiState.sheetsState.exportState).to.equal(SheetState_1.ExportState.OverwritePrompt); chai_1.expect(updateCount).to.equal(0); })); it("Export after prompt check succeeds", () => __awaiter(void 0, void 0, void 0, function* () { var _c, _d; const appState = createAppStateForExport(); let getCount = 0; const mockSheetsApi = createMockApi({ batchGet: () => { getCount++; return Promise.resolve({ success: true, valueRanges: [ { values: