Skip to content

Commit 033c7cf

Browse files
authored
refactor: move some test state to solid signals (@Miodec) (#8025)
1 parent 29f8924 commit 033c7cf

5 files changed

Lines changed: 48 additions & 62 deletions

File tree

frontend/src/ts/pages/test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import * as TestStats from "../test/test-stats";
21
import * as TestLogic from "../test/test-logic";
32
import * as Funbox from "../test/funbox/funbox";
43
import Page from "./page";
@@ -7,6 +6,7 @@ import * as ModesNotice from "../elements/modes-notice";
76
import * as Keymap from "../elements/keymap";
87
import { blurInputElement } from "../input/input-element";
98
import { qsr } from "../utils/dom";
9+
import { resetIncompleteTests } from "../states/test";
1010

1111
export const page = new Page({
1212
id: "test",
@@ -25,7 +25,7 @@ export const page = new Page({
2525
},
2626
beforeShow: async (): Promise<void> => {
2727
updateFooterAndVerticalAds(false);
28-
TestStats.resetIncomplete();
28+
resetIncompleteTests();
2929
TestLogic.restart({
3030
noAnim: true,
3131
});

frontend/src/ts/states/test.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
import { createSignal, createEffect } from "solid-js";
1+
import { createSignal, createEffect, createMemo } from "solid-js";
22
import { Challenge } from "@monkeytype/schemas/challenges";
33
import { getConfig } from "../config/store";
44
import { getActivePage } from "./core";
55
import { canQuickRestart } from "../utils/quick-restart";
66
import { getData as getCustomTextData } from "../test/custom-text";
77
import { isCustomTextLong } from "../legacy-states/custom-text-name";
8+
import { CompletedEvent, IncompleteTest } from "@monkeytype/schemas/results";
9+
import { createSignalWithSetters } from "../hooks/createSignalWithSetters";
810

911
export const [wordsHaveNewline, setWordsHaveNewline] = createSignal(false);
1012
export const [wordsHaveTab, setWordsHaveTab] = createSignal(false);
@@ -13,8 +15,24 @@ export const [getLoadedChallenge, setLoadedChallenge] =
1315
createSignal<Challenge | null>(null);
1416
export const [getResultVisible, setResultVisible] = createSignal(false);
1517
export const [getFocus, setFocus] = createSignal(false);
16-
18+
export const [isTestInvalid, setIsTestInvalid] = createSignal(false);
1719
export const [isLongTest, setIsLongTest] = createSignal(false);
20+
export const [getLastResult, setLastResult] = createSignal<Omit<
21+
CompletedEvent,
22+
"hash" | "uid"
23+
> | null>(null);
24+
export const [
25+
getIncompleteTests,
26+
{ push: pushIncompleteTest, reset: resetIncompleteTests },
27+
] = createSignalWithSetters<IncompleteTest[]>([])({
28+
push: (set, val: IncompleteTest) => set((arr) => [...arr, val]),
29+
reset: (set) => set([]),
30+
});
31+
32+
export const getRestartCount = createMemo(() => getIncompleteTests().length);
33+
export const getIncompleteSeconds = createMemo(() =>
34+
getIncompleteTests().reduce((sum, test) => sum + test.seconds, 0),
35+
);
1836

1937
createEffect(() => {
2038
getActivePage(); // depend on active page

frontend/src/ts/test/result.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import * as ConnectionState from "../legacy-states/connection";
6161
import { currentQuote } from "./test-words";
6262
import { qs, qsa } from "../utils/dom";
6363
import { getTheme } from "../states/theme";
64+
import { isTestInvalid } from "../states/test";
6465

6566
let result: CompletedEvent;
6667
let minChartVal: number;
@@ -833,7 +834,7 @@ function updateOther(
833834
if (afkDetected) {
834835
otherText += "<br>afk detected";
835836
}
836-
if (TestStats.invalid) {
837+
if (isTestInvalid()) {
837838
otherText += "<br>invalid";
838839
const extra: string[] = [];
839840
if (

frontend/src/ts/test/test-logic.ts

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ import { clearQuoteStats } from "../states/quote-rate";
2929
import * as Result from "./result";
3030
import { getActivePage, isAuthenticated } from "../states/core";
3131
import {
32+
getIncompleteSeconds,
33+
getIncompleteTests,
34+
getRestartCount,
35+
pushIncompleteTest,
36+
resetIncompleteTests,
37+
setIsTestInvalid,
38+
setLastResult,
3239
setResultVisible,
3340
setWordsHaveNewline,
3441
setWordsHaveTab,
@@ -253,10 +260,8 @@ export function restart(options = {} as RestartOptions): void {
253260
const afkseconds = TestStats.calculateAfkSeconds(testSeconds);
254261
let tt = Numbers.roundTo2(testSeconds - afkseconds);
255262
if (tt < 0) tt = 0;
256-
TestStats.incrementIncompleteSeconds(tt);
257-
TestStats.incrementRestartCount();
258263
const acc = Numbers.roundTo2(TestStats.calculateAccuracy());
259-
TestStats.pushIncompleteTest(acc, tt);
264+
pushIncompleteTest({ acc, seconds: tt });
260265
}
261266
}
262267

@@ -297,6 +302,7 @@ export function restart(options = {} as RestartOptions): void {
297302
}
298303

299304
TestTimer.clear();
305+
setIsTestInvalid(false);
300306
TestStats.restart();
301307
TestInput.restart();
302308
TestInput.corrected.reset();
@@ -846,12 +852,10 @@ function buildCompletedEvent(
846852
lazyMode: Config.lazyMode,
847853
timestamp: Date.now(),
848854
language: language,
849-
restartCount: TestStats.restartCount,
850-
incompleteTests: TestStats.incompleteTests,
855+
restartCount: getRestartCount(),
856+
incompleteTests: getIncompleteTests(),
851857
incompleteTestSeconds:
852-
TestStats.incompleteSeconds < 0
853-
? 0
854-
: Numbers.roundTo2(TestStats.incompleteSeconds),
858+
getIncompleteSeconds() < 0 ? 0 : Numbers.roundTo2(getIncompleteSeconds()),
855859
difficulty: Config.difficulty,
856860
blindMode: Config.blindMode,
857861
tags: activeTagsIds,
@@ -1013,7 +1017,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
10131017

10141018
const completedEvent = structuredClone(ce) as CompletedEvent;
10151019

1016-
TestStats.setLastResult(structuredClone(completedEvent));
1020+
setLastResult(structuredClone(completedEvent));
10171021

10181022
///////// completed event ready
10191023

@@ -1036,7 +1040,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
10361040
) {
10371041
showNoticeNotification("Test invalid - inconsistent test duration");
10381042
console.error("Test duration inconsistent", ce.testDuration, dateDur);
1039-
TestStats.setInvalid();
1043+
setIsTestInvalid(true);
10401044
dontSave = true;
10411045
} else if (difficultyFailed) {
10421046
showNoticeNotification(`Test failed - ${failReason}`, {
@@ -1063,16 +1067,16 @@ export async function finish(difficultyFailed = false): Promise<void> {
10631067
(Config.mode === "zen" && completedEvent.testDuration < 15)
10641068
) {
10651069
showNoticeNotification("Test invalid - too short");
1066-
TestStats.setInvalid();
1070+
setIsTestInvalid(true);
10671071
tooShort = true;
10681072
dontSave = true;
10691073
} else if (afkDetected) {
10701074
showNoticeNotification("Test invalid - AFK detected");
1071-
TestStats.setInvalid();
1075+
setIsTestInvalid(true);
10721076
dontSave = true;
10731077
} else if (TestState.isRepeated) {
10741078
showNoticeNotification("Test invalid - repeated");
1075-
TestStats.setInvalid();
1079+
setIsTestInvalid(true);
10761080
dontSave = true;
10771081
} else if (
10781082
completedEvent.wpm < 0 ||
@@ -1084,7 +1088,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
10841088
completedEvent.mode2 === "10")
10851089
) {
10861090
showNoticeNotification("Test invalid - wpm");
1087-
TestStats.setInvalid();
1091+
setIsTestInvalid(true);
10881092
dontSave = true;
10891093
} else if (
10901094
completedEvent.rawWpm < 0 ||
@@ -1096,7 +1100,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
10961100
completedEvent.mode2 === "10")
10971101
) {
10981102
showNoticeNotification("Test invalid - raw");
1099-
TestStats.setInvalid();
1103+
setIsTestInvalid(true);
11001104
dontSave = true;
11011105
} else if (
11021106
(!DB.getSnapshot()?.lbOptOut &&
@@ -1105,7 +1109,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
11051109
(completedEvent.acc < 50 || completedEvent.acc > 100))
11061110
) {
11071111
showNoticeNotification("Test invalid - accuracy");
1108-
TestStats.setInvalid();
1112+
setIsTestInvalid(true);
11091113
dontSave = true;
11101114
}
11111115

@@ -1118,9 +1122,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
11181122
let tt = Numbers.roundTo2(testSeconds - afkseconds);
11191123
if (tt < 0) tt = 0;
11201124
const acc = completedEvent.acc;
1121-
TestStats.incrementIncompleteSeconds(tt);
1122-
TestStats.incrementRestartCount();
1123-
TestStats.pushIncompleteTest(acc, tt);
1125+
pushIncompleteTest({ acc, seconds: tt });
11241126
}
11251127
}
11261128

@@ -1180,7 +1182,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
11801182
if (dontSave) {
11811183
void AnalyticsController.log("testCompletedInvalid");
11821184
} else {
1183-
TestStats.resetIncomplete();
1185+
resetIncompleteTests();
11841186

11851187
if (!completedEvent.bailedOut) {
11861188
const challenge = ChallengeContoller.verify(completedEvent);

frontend/src/ts/test/test-stats.ts

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import * as TestInput from "./test-input";
55
import * as TestWords from "./test-words";
66
import * as TestState from "./test-state";
77
import * as Numbers from "@monkeytype/util/numbers";
8-
import { CompletedEvent, IncompleteTest } from "@monkeytype/schemas/results";
98
import { isFunboxActiveWithProperty } from "./funbox/list";
109
import * as CustomText from "./custom-text";
10+
import { getLastResult } from "../states/test";
1111

1212
type CharCount = {
1313
spaces: number;
@@ -33,21 +33,14 @@ export type Stats = {
3333
correctSpaces: number;
3434
};
3535

36-
export let invalid = false;
3736
export let start: number, end: number;
3837
export let start2: number, end2: number;
3938
export let start3: number, end3: number;
4039
export let lastSecondNotRound = false;
4140

42-
export let lastResult: Omit<CompletedEvent, "hash" | "uid">;
43-
44-
export function setLastResult(result: CompletedEvent): void {
45-
lastResult = result;
46-
}
47-
4841
export function getStats(): unknown {
4942
const ret = {
50-
lastResult,
43+
lastResult: getLastResult(),
5144
start,
5245
end,
5346
start3,
@@ -106,37 +99,9 @@ export function getStats(): unknown {
10699
export function restart(): void {
107100
start = 0;
108101
end = 0;
109-
invalid = false;
110102
lastSecondNotRound = false;
111103
}
112104

113-
export let restartCount = 0;
114-
export let incompleteSeconds = 0;
115-
116-
export let incompleteTests: IncompleteTest[] = [];
117-
118-
export function incrementRestartCount(): void {
119-
restartCount++;
120-
}
121-
122-
export function incrementIncompleteSeconds(val: number): void {
123-
incompleteSeconds += val;
124-
}
125-
126-
export function pushIncompleteTest(acc: number, seconds: number): void {
127-
incompleteTests.push({ acc, seconds });
128-
}
129-
130-
export function resetIncomplete(): void {
131-
restartCount = 0;
132-
incompleteSeconds = 0;
133-
incompleteTests = [];
134-
}
135-
136-
export function setInvalid(): void {
137-
invalid = true;
138-
}
139-
140105
export function calculateTestSeconds(now?: number): number {
141106
let duration = (end - start) / 1000;
142107

0 commit comments

Comments
 (0)