modaq
Version:
Quiz Bowl Reader using TypeScript, React, and MobX
914 lines • 65.6 kB
JavaScript
"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: