Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 35 additions & 22 deletions frontend/__tests__/test/events/stats.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,25 @@ vi.mock("../../../src/ts/config/store", () => ({
}));

vi.mock("../../../src/ts/test/test-words", () => {
const list: string[] = [];
type CommitChar = " " | "\n" | "";
type Word = { text: string; textWithCommit: string; commit: CommitChar };
const list: Word[] = [];
return {
words: {
list,
getText(i?: number) {
if (i === undefined) return list;
return list[i];
push(word: string) {
let commit: CommitChar = "";
if (word.endsWith(" ")) {
commit = " ";
word = word.slice(0, -1);
} else if (word.endsWith("\n")) {
commit = "\n";
word = word.slice(0, -1);
}
list.push({ text: word, textWithCommit: word + commit, commit });
},
getCurrentText() {
return list[list.length - 1] ?? "";
reset() {
list.length = 0;
},
},
};
Expand Down Expand Up @@ -79,6 +88,10 @@ import { Keycode } from "../../../src/ts/constants/keys";
import * as TestState from "../../../src/ts/test/test-state";
import { words as TestWords } from "../../../src/ts/test/test-words";

function pushWords(...words: string[]): void {
words.forEach((word, i) => TestWords.push(word, i));
}

function keyDown(code: Keycode = "KeyA"): KeydownEventData {
return { code };
}
Expand Down Expand Up @@ -170,7 +183,7 @@ describe("stats.ts", () => {
(Config as { words: number }).words = 25;
(Config as { time: number }).time = 0;
(TestState as { activeWordIndex: number }).activeWordIndex = 0;
TestWords.list.length = 0;
TestWords.reset();
inputPerWord.clear();
});

Expand Down Expand Up @@ -695,7 +708,7 @@ describe("stats.ts", () => {
// sentinel + "=" together, which monkeytype interprets as crossing the
// word boundary → goToPreviousWord. Word 1 is abandoned with leftover
// "=" residue in its event stream; its final state should still be "".
TestWords.list.push("hello", "leave");
pushWords("hello", "leave");

logTestEvent("timer", 1000, timer("start", 0));
logTestEvent(
Expand Down Expand Up @@ -1014,36 +1027,36 @@ describe("stats.ts", () => {
});

it("returns word without trailing space when it ends with newline", () => {
TestWords.list.push("hello\n");
pushWords("hello\n");
expect(
statsTesting.getTargetWord(buildEventLog(), 0, "hello", false),
).toBe("hello\n");
});

it("appends trailing space for non-last word", () => {
TestWords.list.push("hello");
pushWords("hello");
expect(
statsTesting.getTargetWord(buildEventLog(), 0, "hello", false),
).toBe("hello ");
});

it("does not append trailing space for last word", () => {
TestWords.list.push("hello");
pushWords("hello");
expect(
statsTesting.getTargetWord(buildEventLog(), 0, "hello", true),
).toBe("hello");
});

it("does not append trailing space when nospace funbox is active", () => {
TestWords.list.push("hello");
pushWords("hello");
(Config as { funbox: string[] }).funbox = ["nospace"];
expect(
statsTesting.getTargetWord(buildEventLog(), 0, "hello", false),
).toBe("hello");
});

it("does not append trailing space when underscore_spaces funbox is active", () => {
TestWords.list.push("hello");
pushWords("hello");
(Config as { funbox: string[] }).funbox = ["underscore_spaces"];
expect(
statsTesting.getTargetWord(buildEventLog(), 0, "hello", false),
Expand All @@ -1053,7 +1066,7 @@ describe("stats.ts", () => {

describe("getChars", () => {
it("counts all correct for a perfectly typed word", () => {
TestWords.list.push("hello");
pushWords("hello");
(TestState as { activeWordIndex: number }).activeWordIndex = 0;

logTestEvent("timer", 1000, timer("start", 0));
Expand All @@ -1074,7 +1087,7 @@ describe("stats.ts", () => {
});

it("counts incorrect chars", () => {
TestWords.list.push("ab");
pushWords("ab");
(TestState as { activeWordIndex: number }).activeWordIndex = 0;

logTestEvent("timer", 1000, timer("start", 0));
Expand All @@ -1095,7 +1108,7 @@ describe("stats.ts", () => {
});

it("counts extra chars", () => {
TestWords.list.push("ab");
pushWords("ab");
(TestState as { activeWordIndex: number }).activeWordIndex = 0;

logTestEvent("timer", 1000, timer("start", 0));
Expand All @@ -1120,7 +1133,7 @@ describe("stats.ts", () => {
});

it("counts missed chars for completed non-last words", () => {
TestWords.list.push("hello", "world");
pushWords("hello", "world");
(TestState as { activeWordIndex: number }).activeWordIndex = 1;

logTestEvent("timer", 1000, timer("start", 0));
Expand Down Expand Up @@ -1166,7 +1179,7 @@ describe("stats.ts", () => {
it("credits a word committed with an IME full-width space", () => {
// Japanese IME commits words with the ideographic space U+3000, while the
// target word separator is a regular space — normalize so it still counts
TestWords.list.push("しり", "かこ");
pushWords("しり", "かこ");
(TestState as { activeWordIndex: number }).activeWordIndex = 1;

logTestEvent("timer", 1000, timer("start", 0));
Expand Down Expand Up @@ -1206,7 +1219,7 @@ describe("stats.ts", () => {

describe("getWpmHistory", () => {
it("returns wpm at each timer boundary", () => {
TestWords.list.push("hello");
pushWords("hello");
(TestState as { activeWordIndex: number }).activeWordIndex = 0;

logTestEvent("timer", 1000, timer("start", 0));
Expand All @@ -1227,7 +1240,7 @@ describe("stats.ts", () => {
});

it("returns cumulative wpm across boundaries", () => {
TestWords.list.push("ab", "cd");
pushWords("ab", "cd");
(TestState as { activeWordIndex: number }).activeWordIndex = 1;

logTestEvent("timer", 1000, timer("start", 0));
Expand Down Expand Up @@ -1272,7 +1285,7 @@ describe("stats.ts", () => {

it("counts non-last word as correct without trailing space when nospace funbox is active", () => {
(Config as { funbox: string[] }).funbox = ["nospace"];
TestWords.list.push("ab", "cd");
pushWords("ab", "cd");
(TestState as { activeWordIndex: number }).activeWordIndex = 1;

logTestEvent("timer", 1000, timer("start", 0));
Expand Down Expand Up @@ -1306,7 +1319,7 @@ describe("stats.ts", () => {
});

it("counts multiline word as correct when target ends in newline", () => {
TestWords.list.push("hello\n", "world");
pushWords("hello\n", "world");
(TestState as { activeWordIndex: number }).activeWordIndex = 1;

logTestEvent("timer", 1000, timer("start", 0));
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/ts/commandline/lists/result-screen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,10 @@ const commands: Command[] = [
const words =
Config.mode === "zen"
? inputHistory.join("")
: TestWords.words.list.slice(0, inputHistory.length).join(" ");
: TestWords.words.list
.slice(0, inputHistory.length)
.map((word) => word.text)
Comment thread
Miodec marked this conversation as resolved.
.join(" ");
Comment thread
Miodec marked this conversation as resolved.

navigator.clipboard.writeText(words).then(
() => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/ts/elements/caret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ export class Caret {
const word = wordsCache.qs(
`.word[data-wordindex="${options.wordIndex}"]`,
);
const wordText = TestWords.words.getText(options.wordIndex) ?? "";
const wordText = TestWords.words.get(options.wordIndex)?.display ?? "";
const wordLength = Array.from(wordText).length;

// caret can be either on the left side of the target letter or the right
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/ts/input/handlers/before-delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ export function onBeforeDelete(event: InputEvent): void {
}

const confidence = Config.confidenceMode;
const previousWord = TestWords.words.get(TestState.activeWordIndex - 1);
const previousWordCorrect =
getInputForWord(TestState.activeWordIndex - 1) ===
TestWords.words.getText(TestState.activeWordIndex - 1);
previousWord?.textWithCommit;

if (confidence === "on" && inputIsEmpty && !previousWordCorrect) {
event.preventDefault();
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/ts/input/handlers/before-insert-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ export function onBeforeInsertText(data: string): boolean {
}

const { inputValue } = getInputElementValue();
const currentWordTextWithCommit =
TestWords.words.getCurrent()?.textWithCommit ?? "";
const dataIsSpace = isSpace(data);
const shouldInsertSpaceAsCharacter = shouldInsertSpaceCharacter({
data,
inputValue,
targetWord: TestWords.words.getCurrentText(),
targetWord: currentWordTextWithCommit,
});

//prevent space from being inserted if input is empty
Expand All @@ -60,7 +62,7 @@ export function onBeforeInsertText(data: string): boolean {

// block input if the word is too long
const inputLimit =
Config.mode === "zen" ? 30 : TestWords.words.getCurrentText().length + 20;
Config.mode === "zen" ? 30 : currentWordTextWithCommit.length + 20;
const overLimit = getCurrentInput().length >= inputLimit;
if (overLimit && (shouldInsertSpaceAsCharacter === true || !dataIsSpace)) {
console.error("Hitting word limit");
Expand All @@ -71,7 +73,7 @@ export function onBeforeInsertText(data: string): boolean {
// this will not work for the first word of each line, but that has a low chance of happening
const dataIsNotFalsy = data !== null && data !== "";
const inputIsLongerThanOrEqualToWord =
getCurrentInput().length >= TestWords.words.getCurrentText().length;
getCurrentInput().length >= currentWordTextWithCommit.length;

if (
!SlowTimer.get() && // don't do this check if slow timer is active
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/ts/input/handlers/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export function onDelete(inputType: DeleteInputType, now: number): void {

const beforeDeleteOnlyTabs = /^\t*$/.test(inputBeforeDelete);
const allTabsCorrect = TestWords.words
.getCurrentText()
.startsWith(inputAfterDelete);
.getCurrent()
?.textWithCommit.startsWith(inputAfterDelete);

//special check for code languages
if (
Expand Down
15 changes: 9 additions & 6 deletions frontend/src/ts/input/handlers/insert-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ export async function onInsertText(options: OnInsertTextParams): Promise<void> {
const charOverride = charOverrides.get(options.data);
if (
charOverride !== undefined &&
TestWords.words.getCurrentText()[getCurrentInput().length] !== options.data
TestWords.words.getCurrent()?.textWithCommit[getCurrentInput().length] !==
options.data
) {
// replace the data with the override
setInputElementValue(
Expand All @@ -107,8 +108,9 @@ export async function onInsertText(options: OnInsertTextParams): Promise<void> {
for (const [targetChar, overrideChar] of languageOverrides) {
if (
options.data === targetChar &&
TestWords.words.getCurrentText()[getCurrentInput().length] !==
options.data
TestWords.words.getCurrent()?.textWithCommit[
getCurrentInput().length
] !== options.data
) {
// replace the data with the override
setInputElementValue(
Expand All @@ -125,7 +127,7 @@ export async function onInsertText(options: OnInsertTextParams): Promise<void> {

// input and target word
const testInput = getCurrentInput();
const currentWord = TestWords.words.getCurrentText();
const currentWord = TestWords.words.getCurrent()?.textWithCommit ?? "";

// if the character is visually equal, replace it with the target character
// this ensures all future equivalence checks work correctly
Expand Down Expand Up @@ -167,7 +169,8 @@ export async function onInsertText(options: OnInsertTextParams): Promise<void> {
// word navigation check
const noSpaceForce =
isFunboxActiveWithProperty("nospace") &&
(testInput + data).length === TestWords.words.getCurrentText().length;
(testInput + data).length ===
TestWords.words.getCurrent()?.textWithCommit.length;
// does this input try to move to the next word (before removeLastChar can block it)
const goingToNextWord =
((charIsSpace || charIsNewline) && !shouldInsertSpace) || noSpaceForce;
Expand Down Expand Up @@ -273,7 +276,7 @@ export async function onInsertText(options: OnInsertTextParams): Promise<void> {
*/

//this COULD be the next word because we are awaiting goToNextWord
const nextWord = TestWords.words.getCurrentText();
const nextWord = TestWords.words.getCurrent()?.textWithCommit ?? "";
const doesNextWordHaveTab = /^\t+/.test(nextWord);
const isCurrentCharTab = nextWord[getCurrentInput().length] === "\t";

Expand Down
9 changes: 6 additions & 3 deletions frontend/src/ts/input/helpers/word-navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,12 @@ export async function goToNextWord({
ret.lastBurst = burst;
}

PaceCaret.handleSpace(correctInsert, TestWords.words.getCurrentText());
PaceCaret.handleSpace(
correctInsert,
TestWords.words.getCurrent()?.textWithCommit ?? "",
);

const nextWord = TestWords.words.getText(TestState.activeWordIndex + 1);
const nextWord = TestWords.words.get(TestState.activeWordIndex + 1)?.text;
if (nextWord !== undefined) Funbox.toggleScript(nextWord);

const lastWord = TestState.activeWordIndex >= TestWords.words.length - 1;
Expand Down Expand Up @@ -98,7 +101,7 @@ export function goToPreviousWord(

TestState.decreaseActiveWordIndex();

const word = TestWords.words.getText(TestState.activeWordIndex);
const word = TestWords.words.get(TestState.activeWordIndex)?.text;
if (word !== undefined) Funbox.toggleScript(word);

const nospaceEnabled = isFunboxActiveWithProperty("nospace");
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/ts/input/listeners/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ inputEl.addEventListener("input", async (event) => {
const inputPlusComposition =
getCurrentInput() + (CompositionState.getData() ?? "");
const inputPlusCompositionIsCorrect =
TestWords.words.getCurrentText() === inputPlusComposition;
TestWords.words.getCurrent()?.textWithCommit === inputPlusComposition;

// composition quick end
// if the user typed the entire word correctly but is still in composition
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/ts/test/events/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { isFunboxActiveWithProperty } from "../funbox/active";

export function buildEventLog(): EventLog {
const context = {
targetWords: [...TestWords.words.list],
targetWords: [...TestWords.words.list.map((w) => w.textWithCommit)],
mode: Config.mode,
mode2: getMode2(Config, getCurrentQuote()),
koreanStatus: koreanStatus,
Expand Down
19 changes: 14 additions & 5 deletions frontend/src/ts/test/funbox/funbox-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,25 @@ export type FunboxFunctions = {

async function readAheadHandleKeydown(event: KeyboardEvent): Promise<void> {
const currentInput = getCurrentInput();
const currentWord = TestWords.words.getCurrent();

if (!currentWord) {
return;
}

const inputCurrentChar = currentInput.slice(-1);
const wordCurrentChar = TestWords.words
.getCurrentText()
.slice(currentInput.length - 1, currentInput.length);
const wordCurrentChar = currentWord.display.slice(
currentInput.length - 1,
currentInput.length,
);
const isCorrect = inputCurrentChar === wordCurrentChar;

if (
event.key === "Backspace" &&
!isCorrect &&
(currentInput !== "" ||
getInputForWord(TestState.activeWordIndex - 1) !==
TestWords.words.getText(TestState.activeWordIndex - 1) ||
TestWords.words.get(TestState.activeWordIndex - 1)?.display ||
Config.freedomMode)
) {
qs("#words")?.addClass("read_ahead_disabled");
Expand Down Expand Up @@ -416,7 +423,9 @@ const list: Partial<Record<FunboxName, FunboxFunctions>> = {
}
setTimeout(() => {
highlight(
TestWords.words.getCurrentText().charAt(getCurrentInput().length),
TestWords.words
.getCurrent()
?.text.charAt(getCurrentInput().length) ?? "",
);
}, 1);
}
Expand Down
Loading
Loading