diff --git a/.gitignore b/.gitignore
index 788a04ad74ca..0b4945d42bb3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -67,6 +67,7 @@ node_modules_bak/
# dotenv environment variables file
.env
+.env*
#vs code
.vscode/*
diff --git a/frontend/src/html/popups.html b/frontend/src/html/popups.html
index bbe596c993b9..686dd1306e99 100644
--- a/frontend/src/html/popups.html
+++ b/frontend/src/html/popups.html
@@ -68,6 +68,7 @@
+
diff --git a/frontend/src/ts/input/handlers/insert-text.ts b/frontend/src/ts/input/handlers/insert-text.ts
index b3c1f67ca22c..598336af93b1 100644
--- a/frontend/src/ts/input/handlers/insert-text.ts
+++ b/frontend/src/ts/input/handlers/insert-text.ts
@@ -69,6 +69,7 @@ export async function onInsertText(options: OnInsertTextParams): Promise {
// make sure to not call TestInput.input.syncWithInputElement in here
// it will be updated later in the body of onInsertText
setInputElementValue(inputValue.slice(0, -options.data.length));
+ TestInput.input.syncWithInputElement();
for (let i = 0; i < options.data.length; i++) {
const char = options.data[i] as string;
diff --git a/frontend/src/ts/input/handlers/keydown.ts b/frontend/src/ts/input/handlers/keydown.ts
index dc87f89f3459..4bbe80224e84 100644
--- a/frontend/src/ts/input/handlers/keydown.ts
+++ b/frontend/src/ts/input/handlers/keydown.ts
@@ -152,12 +152,6 @@ async function handleFunboxes(
}
export async function onKeydown(event: KeyboardEvent): Promise {
- console.debug("wordsInput event keydown", {
- event,
- key: event.key,
- code: event.code,
- });
-
const now = performance.now();
TestInput.recordKeydownTime(now, event);
diff --git a/frontend/src/ts/input/input-element.ts b/frontend/src/ts/input/input-element.ts
index 44b1de1edab0..6d8c0a946232 100644
--- a/frontend/src/ts/input/input-element.ts
+++ b/frontend/src/ts/input/input-element.ts
@@ -1,10 +1,10 @@
-const el = document.querySelector("#wordsInput") as HTMLInputElement;
+const el = document.querySelector("#wordsInput") as HTMLTextAreaElement;
if (el === null) {
throw new Error("Words input element not found");
}
-export function getInputElement(): HTMLInputElement {
+export function getInputElement(): HTMLTextAreaElement {
return el;
}
diff --git a/frontend/src/ts/input/listeners/misc.ts b/frontend/src/ts/input/listeners/misc.ts
index 10e985070c4e..8c49762e0c44 100644
--- a/frontend/src/ts/input/listeners/misc.ts
+++ b/frontend/src/ts/input/listeners/misc.ts
@@ -20,20 +20,17 @@ inputEl.addEventListener("select selectstart", (event) => {
inputEl.addEventListener("selectionchange", (event) => {
const selection = window.getSelection();
+
console.debug("wordsInput event selectionchange", {
event,
selection: selection?.toString(),
isCollapsed: selection?.isCollapsed,
- selectionStart: (event.target as HTMLInputElement).selectionStart,
- selectionEnd: (event.target as HTMLInputElement).selectionEnd,
+ selectionStart: inputEl.selectionStart,
+ selectionEnd: inputEl.selectionEnd,
});
- const el = event.target;
- if (el === null || !(el instanceof HTMLInputElement)) {
- return;
- }
- const hasSelectedText = el.selectionStart !== el.selectionEnd;
- const isCursorAtEnd = el.selectionStart === el.value.length;
+ const hasSelectedText = inputEl.selectionStart !== inputEl.selectionEnd;
+ const isCursorAtEnd = inputEl.selectionStart === inputEl.value.length;
if (hasSelectedText || !isCursorAtEnd) {
moveInputElementCaretToTheEnd();
}
diff --git a/frontend/src/ts/modals/dev-options.ts b/frontend/src/ts/modals/dev-options.ts
index 36c632e53dc4..9742c6e8832c 100644
--- a/frontend/src/ts/modals/dev-options.ts
+++ b/frontend/src/ts/modals/dev-options.ts
@@ -9,6 +9,7 @@ import { update } from "../elements/xp-bar";
import { toggleUserFakeChartData } from "../test/result";
import { toggleCaretDebug } from "../utils/caret";
import { getInputElement } from "../input/input-element";
+import { disableSlowTimerFail } from "../test/test-timer";
let mediaQueryDebugLevel = 0;
@@ -94,6 +95,11 @@ async function setup(modalEl: HTMLElement): Promise {
modalEl.querySelector(".toggleCaretDebug")?.addEventListener("click", () => {
toggleCaretDebug();
});
+ modalEl
+ .querySelector(".disableSlowTimerFail")
+ ?.addEventListener("click", () => {
+ disableSlowTimerFail();
+ });
}
const modal = new AnimatedModal({
diff --git a/frontend/src/ts/test/test-timer.ts b/frontend/src/ts/test/test-timer.ts
index 3418ebc3dcb1..e0acebbd408b 100644
--- a/frontend/src/ts/test/test-timer.ts
+++ b/frontend/src/ts/test/test-timer.ts
@@ -32,6 +32,11 @@ let timer: NodeJS.Timeout | null = null;
const interval = 1000;
let expected = 0;
+let slowTimerFailEnabled = true;
+export function disableSlowTimerFail(): void {
+ slowTimerFailEnabled = false;
+}
+
let timerDebug = false;
export function enableTimerDebug(): void {
timerDebug = true;
@@ -234,30 +239,32 @@ export async function start(): Promise {
expected: expected,
nextDelay: delay,
});
- if (
- (Config.mode === "time" && Config.time < 130 && Config.time > 0) ||
- (Config.mode === "words" && Config.words < 250 && Config.words > 0)
- ) {
- if (delay < interval / 2) {
- //slow timer
- SlowTimer.set();
- setLowFpsMode();
- }
- if (delay < interval / 10) {
- slowTimerCount++;
- if (slowTimerCount > 5) {
+ if (slowTimerFailEnabled) {
+ if (
+ (Config.mode === "time" && Config.time < 130 && Config.time > 0) ||
+ (Config.mode === "words" && Config.words < 250 && Config.words > 0)
+ ) {
+ if (delay < interval / 2) {
//slow timer
-
- Notifications.add(
- 'This could be caused by "efficiency mode" on Microsoft Edge.',
- );
-
- Notifications.add(
- "Stopping the test due to bad performance. This would cause test calculations to be incorrect. If this happens a lot, please report this.",
- -1,
- );
-
- TimerEvent.dispatch("fail", "slow timer");
+ SlowTimer.set();
+ setLowFpsMode();
+ }
+ if (delay < interval / 10) {
+ slowTimerCount++;
+ if (slowTimerCount > 5) {
+ //slow timer
+
+ Notifications.add(
+ 'This could be caused by "efficiency mode" on Microsoft Edge.',
+ );
+
+ Notifications.add(
+ "Stopping the test due to bad performance. This would cause test calculations to be incorrect. If this happens a lot, please report this.",
+ -1,
+ );
+
+ TimerEvent.dispatch("fail", "slow timer");
+ }
}
}
}
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
index bf2572157c8f..dc08c12fdfbe 100644
--- a/frontend/vite.config.js
+++ b/frontend/vite.config.js
@@ -1,12 +1,17 @@
import { defineConfig, mergeConfig } from "vite";
import injectHTML from "vite-plugin-html-inject";
import autoprefixer from "autoprefixer";
-import "dotenv/config";
+import { config as dotenvConfig } from "dotenv";
import PROD_CONFIG from "./vite.config.prod";
import DEV_CONFIG from "./vite.config.dev";
import MagicString from "magic-string";
import { Fonts } from "./src/ts/constants/fonts";
+// Load environment variables based on NODE_ENV
+const envFile =
+ process.env.NODE_ENV === "production" ? ".env.production" : ".env";
+dotenvConfig({ path: envFile });
+
/** @type {import("vite").UserConfig} */
const BASE_CONFIG = {
plugins: [
@@ -63,8 +68,13 @@ const BASE_CONFIG = {
export default defineConfig(({ command }) => {
if (command === "build") {
+ const envFileName =
+ process.env.NODE_ENV === "production" ? ".env.production" : ".env";
if (process.env.RECAPTCHA_SITE_KEY === undefined) {
- throw new Error(".env: RECAPTCHA_SITE_KEY is not defined");
+ throw new Error(`${envFileName}: RECAPTCHA_SITE_KEY is not defined`);
+ }
+ if (process.env.SENTRY && process.env.SENTRY_AUTH_TOKEN === undefined) {
+ throw new Error(`${envFileName}: SENTRY_AUTH_TOKEN is not defined`);
}
return mergeConfig(BASE_CONFIG, PROD_CONFIG);
} else {
diff --git a/packages/release/src/index.js b/packages/release/src/index.js
index f48ed7071096..dfbca0a07e97 100755
--- a/packages/release/src/index.js
+++ b/packages/release/src/index.js
@@ -179,15 +179,15 @@ const buildProject = () => {
if (isFrontend && !isBackend) {
runProjectRootCommand(
- "SENTRY=1 npx turbo lint test check-assets build --filter @monkeytype/frontend --force",
+ "NODE_ENV=production SENTRY=1 npx turbo lint test check-assets build --filter @monkeytype/frontend --force",
);
} else if (isBackend && !isFrontend) {
runProjectRootCommand(
- "SENTRY=1 npx turbo lint test build --filter @monkeytype/backend --force",
+ "NODE_ENV=production SENTRY=1 npx turbo lint test build --filter @monkeytype/backend --force",
);
} else {
runProjectRootCommand(
- "SENTRY=1 npx turbo lint test check-assets build --force",
+ "NODE_ENV=production SENTRY=1 npx turbo lint test check-assets build --force",
);
}
};