From 80b4fd720b1e3813bea3eae185be5e9857dab3a7 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Fri, 16 Feb 2024 11:24:32 +0100 Subject: [PATCH 01/11] fix: Use selected typing speed unit on personal best popup --- frontend/src/ts/popups/pb-tables-popup.ts | 36 +++++++++++++++++++---- frontend/static/html/popups.html | 2 +- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/frontend/src/ts/popups/pb-tables-popup.ts b/frontend/src/ts/popups/pb-tables-popup.ts index ae48e9574f12..aa3c23514f0e 100644 --- a/frontend/src/ts/popups/pb-tables-popup.ts +++ b/frontend/src/ts/popups/pb-tables-popup.ts @@ -2,6 +2,9 @@ import * as DB from "../db"; import format from "date-fns/format"; import * as Skeleton from "./skeleton"; import { getLanguageDisplayString, isPopupVisible } from "../utils/misc"; +import Config from "../config"; +import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; +import * as Misc from "../utils/misc"; type PersonalBest = { mode2: SharedTypes.Config.Mode2; @@ -12,6 +15,9 @@ const wrapperId = "pbTablesPopupWrapper"; function update(mode: SharedTypes.Config.Mode): void { $("#pbTablesPopup table tbody").empty(); $($("#pbTablesPopup table thead tr td")[0] as HTMLElement).text(mode); + $($("#pbTablesPopup table thead tr td span.unit")[0] as HTMLElement).text( + Config.typingSpeedUnit + ); const snapshot = DB.getSnapshot(); if (!snapshot) return; @@ -56,16 +62,14 @@ function update(mode: SharedTypes.Config.Mode): void { ${mode2memory === pb.mode2 ? "" : pb.mode2} - ${pb.wpm.toFixed(2)} + ${formatTypingSpeed(pb.wpm)}
- ${pb.acc ? pb.acc + "%" : "-"} + ${formatPercentage(pb.acc)} - ${pb.raw ? pb.raw : "-"} + ${formatTypingSpeed(pb.raw)}
- ${ - pb.consistency ? pb.consistency + "%" : "-" - } + ${formatPercentage(pb.consistency)} ${pb.difficulty} ${pb.language ? getLanguageDisplayString(pb.language) : "-"} @@ -134,3 +138,23 @@ $(document).on("keydown", (event) => { }); Skeleton.save(wrapperId); + +function formatTypingSpeed(wpm?: number): string { + if (wpm === undefined || wpm === null) return "-"; + + const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit); + const result = typingSpeedUnit.fromWpm(wpm); + if (Config.alwaysShowDecimalPlaces) { + return Misc.roundTo2(result).toFixed(2); + } + return Math.round(result).toString(); +} + +function formatPercentage(percentage?: number): string { + if (percentage === undefined || percentage === null) return "-"; + + if (Config.alwaysShowDecimalPlaces) { + return Misc.roundTo2(percentage).toFixed(2) + "%"; + } + return Math.round(percentage).toString() + "%"; +} diff --git a/frontend/static/html/popups.html b/frontend/static/html/popups.html index 760b4088ffcf..5cc727ca3169 100644 --- a/frontend/static/html/popups.html +++ b/frontend/static/html/popups.html @@ -244,7 +244,7 @@ words - wpm + wpm
accuracy From dfd82fced24148cc4edb1f92ceeede317df60085 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Fri, 16 Feb 2024 11:36:27 +0100 Subject: [PATCH 02/11] refactor --- frontend/src/ts/popups/pb-tables-popup.ts | 23 +--------------- frontend/src/ts/utils/format.ts | 33 +++++++++++++++++++++++ 2 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 frontend/src/ts/utils/format.ts diff --git a/frontend/src/ts/popups/pb-tables-popup.ts b/frontend/src/ts/popups/pb-tables-popup.ts index aa3c23514f0e..e7606f361018 100644 --- a/frontend/src/ts/popups/pb-tables-popup.ts +++ b/frontend/src/ts/popups/pb-tables-popup.ts @@ -3,8 +3,7 @@ import format from "date-fns/format"; import * as Skeleton from "./skeleton"; import { getLanguageDisplayString, isPopupVisible } from "../utils/misc"; import Config from "../config"; -import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; -import * as Misc from "../utils/misc"; +import { formatTypingSpeed, formatPercentage } from "../utils/format"; type PersonalBest = { mode2: SharedTypes.Config.Mode2; @@ -138,23 +137,3 @@ $(document).on("keydown", (event) => { }); Skeleton.save(wrapperId); - -function formatTypingSpeed(wpm?: number): string { - if (wpm === undefined || wpm === null) return "-"; - - const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit); - const result = typingSpeedUnit.fromWpm(wpm); - if (Config.alwaysShowDecimalPlaces) { - return Misc.roundTo2(result).toFixed(2); - } - return Math.round(result).toString(); -} - -function formatPercentage(percentage?: number): string { - if (percentage === undefined || percentage === null) return "-"; - - if (Config.alwaysShowDecimalPlaces) { - return Misc.roundTo2(percentage).toFixed(2) + "%"; - } - return Math.round(percentage).toString() + "%"; -} diff --git a/frontend/src/ts/utils/format.ts b/frontend/src/ts/utils/format.ts new file mode 100644 index 000000000000..d09e66bb8f5f --- /dev/null +++ b/frontend/src/ts/utils/format.ts @@ -0,0 +1,33 @@ +import * as Misc from "./misc"; +import Config from "../config"; +import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; + +export function formatTypingSpeed( + wpm: number | null | undefined, + showDecimals?: boolean, + fallback?: "-" +): string { + if (wpm === undefined || wpm === null) return fallback ?? ""; + const result = getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm(wpm); + if ( + showDecimals !== undefined ? showDecimals : Config.alwaysShowDecimalPlaces + ) { + return Misc.roundTo2(result).toFixed(2); + } + return Math.round(result).toString(); +} + +export function formatPercentage( + percentage: number | null | undefined, + showDecimals?: boolean, + fallback?: "-" +): string { + if (percentage === undefined || percentage === null) return fallback ?? ""; + + if ( + showDecimals !== undefined ? showDecimals : Config.alwaysShowDecimalPlaces + ) { + return Misc.roundTo2(percentage).toFixed(2) + "%"; + } + return Math.round(percentage).toString() + "%"; +} From 159995a1de5c6852b066b5027dfec686c8dc4752 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Sat, 17 Feb 2024 14:55:17 +0100 Subject: [PATCH 03/11] refactor --- frontend/src/ts/account/pb-tables.ts | 59 +++++------------------ frontend/src/ts/popups/pb-tables-popup.ts | 10 ++-- frontend/src/ts/utils/format.ts | 54 ++++++++++++++------- 3 files changed, 53 insertions(+), 70 deletions(-) diff --git a/frontend/src/ts/account/pb-tables.ts b/frontend/src/ts/account/pb-tables.ts index 4fd9e6f328ec..97552d7b0167 100644 --- a/frontend/src/ts/account/pb-tables.ts +++ b/frontend/src/ts/account/pb-tables.ts @@ -2,6 +2,7 @@ import Config from "../config"; import format from "date-fns/format"; import * as Misc from "../utils/misc"; import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; +import * as Format from "../utils/format"; function clearTables(isProfile: boolean): void { const source = isProfile ? "Profile" : "Account"; @@ -151,59 +152,21 @@ function buildPbHtml( dateText = format(date, "dd MMM yyyy"); } - let speedString: number | string = typingSpeedUnit.fromWpm(pbData.wpm); - if (Config.alwaysShowDecimalPlaces) { - speedString = Misc.roundTo2(speedString).toFixed(2); - } else { - speedString = Math.round(speedString); - } - speedString += ` ${speedUnit}`; - - let rawString: number | string = typingSpeedUnit.fromWpm(pbData.raw); - if (Config.alwaysShowDecimalPlaces) { - rawString = Misc.roundTo2(rawString).toFixed(2); - } else { - rawString = Math.round(rawString); - } - rawString += ` raw`; - - let accString: number | string = pbData.acc; - if (accString === undefined) { - accString = "-"; - } else { - if (Config.alwaysShowDecimalPlaces) { - accString = Misc.roundTo2(accString).toFixed(2); - } else { - accString = Math.floor(accString); - } - } - accString += ` acc`; - - let conString: number | string = pbData.consistency; - if (conString === undefined) { - conString = "-"; - } else { - if (Config.alwaysShowDecimalPlaces) { - conString = Misc.roundTo2(conString).toFixed(2); - } else { - conString = Math.round(conString); - } - } - conString += ` con`; - retval = `
${modeString}
-
${Math.round(typingSpeedUnit.fromWpm(pbData.wpm))}
-
${ - pbData.acc === undefined ? "-" : Math.floor(pbData.acc) + "%" - }
+
${Format.typingSpeed(pbData.wpm, { + showDecimalPlaces: false, + })}
+
${Format.percentage(pbData.acc, { + showDecimalPlaces: false, + })}
${modeString}
-
${speedString}
-
${rawString}
-
${accString}
-
${conString}
+
${Format.typingSpeed(pbData.wpm, { suffix: ` ${speedUnit}` })}
+
${Format.typingSpeed(pbData.raw, { suffix: " raw" })}
+
${Format.percentage(pbData.acc, { suffix: " acc" })}
+
${Format.percentage(pbData.consistency, { suffix: " con" })}
${dateText}
`; } catch (e) { diff --git a/frontend/src/ts/popups/pb-tables-popup.ts b/frontend/src/ts/popups/pb-tables-popup.ts index e7606f361018..b0b69da0bea2 100644 --- a/frontend/src/ts/popups/pb-tables-popup.ts +++ b/frontend/src/ts/popups/pb-tables-popup.ts @@ -3,7 +3,7 @@ import format from "date-fns/format"; import * as Skeleton from "./skeleton"; import { getLanguageDisplayString, isPopupVisible } from "../utils/misc"; import Config from "../config"; -import { formatTypingSpeed, formatPercentage } from "../utils/format"; +import * as Format from "../utils/format"; type PersonalBest = { mode2: SharedTypes.Config.Mode2; @@ -61,14 +61,14 @@ function update(mode: SharedTypes.Config.Mode): void { ${mode2memory === pb.mode2 ? "" : pb.mode2} - ${formatTypingSpeed(pb.wpm)} + ${Format.typingSpeed(pb.wpm)}
- ${formatPercentage(pb.acc)} + ${Format.percentage(pb.acc)} - ${formatTypingSpeed(pb.raw)} + ${Format.typingSpeed(pb.raw)}
- ${formatPercentage(pb.consistency)} + ${Format.percentage(pb.consistency)} ${pb.difficulty} ${pb.language ? getLanguageDisplayString(pb.language) : "-"} diff --git a/frontend/src/ts/utils/format.ts b/frontend/src/ts/utils/format.ts index d09e66bb8f5f..48a3e8a78d1e 100644 --- a/frontend/src/ts/utils/format.ts +++ b/frontend/src/ts/utils/format.ts @@ -2,32 +2,52 @@ import * as Misc from "./misc"; import Config from "../config"; import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; -export function formatTypingSpeed( +export type FormatOptions = { + showDecimalPlaces?: boolean; + suffix?: string; + fallback?: string; +}; + +const FORMAT_DEFAULT_OPTIONS: FormatOptions = { + suffix: "", + fallback: "-", +}; + +export function typingSpeed( wpm: number | null | undefined, - showDecimals?: boolean, - fallback?: "-" + formatOptions: FormatOptions = FORMAT_DEFAULT_OPTIONS ): string { - if (wpm === undefined || wpm === null) return fallback ?? ""; + const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions }; + if (wpm === undefined || wpm === null) return options.fallback ?? ""; + const result = getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm(wpm); - if ( - showDecimals !== undefined ? showDecimals : Config.alwaysShowDecimalPlaces - ) { - return Misc.roundTo2(result).toFixed(2); - } - return Math.round(result).toString(); + + return decimals(result, options); } -export function formatPercentage( +export function percentage( percentage: number | null | undefined, - showDecimals?: boolean, - fallback?: "-" + formatOptions: FormatOptions = FORMAT_DEFAULT_OPTIONS +): string { + const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions }; + options.suffix = "%" + (options.suffix ?? ""); + + return decimals(percentage, options); +} + +export function decimals( + value: number | null | undefined, + formatOptions: FormatOptions ): string { - if (percentage === undefined || percentage === null) return fallback ?? ""; + if (value === undefined || value === null) + return formatOptions.fallback ?? ""; if ( - showDecimals !== undefined ? showDecimals : Config.alwaysShowDecimalPlaces + formatOptions.showDecimalPlaces !== undefined + ? formatOptions.showDecimalPlaces + : Config.alwaysShowDecimalPlaces ) { - return Misc.roundTo2(percentage).toFixed(2) + "%"; + return Misc.roundTo2(value).toFixed(2) + (formatOptions.suffix ?? ""); } - return Math.round(percentage).toString() + "%"; + return Math.round(value).toString() + (formatOptions.suffix ?? ""); } From eca2416b596b4fe9ef3406bea6efe752ec402dfc Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Sat, 17 Feb 2024 17:40:31 +0100 Subject: [PATCH 04/11] test coverage --- frontend/__tests__/utils/format.spec.ts | 127 ++++++++++++++++++++++++ frontend/src/ts/utils/format.ts | 8 +- 2 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 frontend/__tests__/utils/format.spec.ts diff --git a/frontend/__tests__/utils/format.spec.ts b/frontend/__tests__/utils/format.spec.ts new file mode 100644 index 000000000000..c626043d11bd --- /dev/null +++ b/frontend/__tests__/utils/format.spec.ts @@ -0,0 +1,127 @@ +import * as Format from "../../src/ts/utils/format"; +import Config from "../../src/ts/config"; + +const configMock: Partial = {}; + +describe("format.ts", () => { + beforeEach(() => { + Config.typingSpeedUnit = "wpm"; + Config.alwaysShowDecimalPlaces = false; + }); + describe("typingsSpeed", () => { + it("should format with typing speed and decimalPlaces from configuration", () => { + //wpm, no decimals + Config.typingSpeedUnit = "wpm"; + Config.alwaysShowDecimalPlaces = false; + expect(Format.typingSpeed(12.5)).toEqual("13"); + expect(Format.typingSpeed(0)).toEqual("0"); + + //cpm, no decimals + Config.typingSpeedUnit = "cpm"; + Config.alwaysShowDecimalPlaces = false; + expect(Format.typingSpeed(12.5)).toEqual("63"); + expect(Format.typingSpeed(0)).toEqual("0"); + + //wpm, with decimals + Config.typingSpeedUnit = "wpm"; + Config.alwaysShowDecimalPlaces = true; + expect(Format.typingSpeed(12.5)).toEqual("12.50"); + expect(Format.typingSpeed(0)).toEqual("0.00"); + + //cpm, with decimals + Config.typingSpeedUnit = "cpm"; + Config.alwaysShowDecimalPlaces = true; + expect(Format.typingSpeed(12.5)).toEqual("62.50"); + expect(Format.typingSpeed(0)).toEqual("0.00"); + }); + + it("should format with fallback", () => { + //default fallback + expect(Format.typingSpeed(null)).toEqual("-"); + expect(Format.typingSpeed(undefined)).toEqual("-"); + + //provided fallback + expect(Format.typingSpeed(null, { fallback: "none" })).toEqual("none"); + expect(Format.typingSpeed(null, { fallback: "" })).toEqual(""); + expect(Format.typingSpeed(undefined, { fallback: "none" })).toEqual( + "none" + ); + + expect(Format.typingSpeed(undefined, { fallback: "" })).toEqual(""); + expect(Format.typingSpeed(undefined, { fallback: undefined })).toEqual( + "" + ); + }); + + it("should format with decimals", () => { + //force with decimals + Config.alwaysShowDecimalPlaces = false; + expect(Format.typingSpeed(100, { showDecimalPlaces: true })).toEqual( + "100.00" + ); + //force without decimals + Config.alwaysShowDecimalPlaces = true; + expect(Format.typingSpeed(100, { showDecimalPlaces: false })).toEqual( + "100" + ); + }); + + it("should format with suffix", () => { + expect(Format.typingSpeed(100, { suffix: " raw" })).toEqual("100 raw"); + expect(Format.typingSpeed(100, { suffix: undefined })).toEqual("100"); + expect(Format.typingSpeed(0, { suffix: " raw" })).toEqual("0 raw"); + expect(Format.typingSpeed(null, { suffix: " raw" })).toEqual("-"); + expect(Format.typingSpeed(undefined, { suffix: " raw" })).toEqual("-"); + }); + }); + describe("percentage", () => { + it("should format with decimalPlaces from configuration", () => { + //no decimals + Config.alwaysShowDecimalPlaces = false; + expect(Format.percentage(12.5)).toEqual("13%"); + expect(Format.percentage(0)).toEqual("0%"); + + //with decimals + Config.alwaysShowDecimalPlaces = true; + expect(Format.percentage(12.5)).toEqual("12.50%"); + expect(Format.percentage(0)).toEqual("0.00%"); + }); + + it("should format with fallback", () => { + //default fallback + expect(Format.percentage(null)).toEqual("-"); + expect(Format.percentage(undefined)).toEqual("-"); + + //provided fallback + expect(Format.percentage(null, { fallback: "none" })).toEqual("none"); + expect(Format.percentage(null, { fallback: "" })).toEqual(""); + expect(Format.percentage(undefined, { fallback: "none" })).toEqual( + "none" + ); + + expect(Format.percentage(undefined, { fallback: "" })).toEqual(""); + expect(Format.percentage(undefined, { fallback: undefined })).toEqual(""); + }); + + it("should format with decimals", () => { + //force with decimals + Config.alwaysShowDecimalPlaces = false; + expect(Format.percentage(100, { showDecimalPlaces: true })).toEqual( + "100.00%" + ); + //force without decimals + Config.alwaysShowDecimalPlaces = true; + expect(Format.percentage(100, { showDecimalPlaces: false })).toEqual( + "100%" + ); + }); + + it("should format with suffix", () => { + expect(Format.percentage(100, { suffix: " raw" })).toEqual("100% raw"); + expect(Format.percentage(100, { suffix: undefined })).toEqual("100%"); + expect(Format.percentage(0, { suffix: " raw" })).toEqual("0% raw"); + expect(Format.percentage(null, { suffix: " raw" })).toEqual("-"); + expect(Format.percentage(undefined, { suffix: " raw" })).toEqual("-"); + }); + }); +}); diff --git a/frontend/src/ts/utils/format.ts b/frontend/src/ts/utils/format.ts index 48a3e8a78d1e..7f7f4ed370c3 100644 --- a/frontend/src/ts/utils/format.ts +++ b/frontend/src/ts/utils/format.ts @@ -11,6 +11,7 @@ export type FormatOptions = { const FORMAT_DEFAULT_OPTIONS: FormatOptions = { suffix: "", fallback: "-", + showDecimalPlaces: undefined, }; export function typingSpeed( @@ -35,19 +36,20 @@ export function percentage( return decimals(percentage, options); } -export function decimals( +function decimals( value: number | null | undefined, formatOptions: FormatOptions ): string { if (value === undefined || value === null) return formatOptions.fallback ?? ""; + const suffix = formatOptions.suffix ?? ""; if ( formatOptions.showDecimalPlaces !== undefined ? formatOptions.showDecimalPlaces : Config.alwaysShowDecimalPlaces ) { - return Misc.roundTo2(value).toFixed(2) + (formatOptions.suffix ?? ""); + return Misc.roundTo2(value).toFixed(2) + suffix; } - return Math.round(value).toString() + (formatOptions.suffix ?? ""); + return Math.round(value).toString() + suffix; } From 8efa8455b356967b92e49d462c204d4afafd1d70 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Sat, 17 Feb 2024 18:23:58 +0100 Subject: [PATCH 05/11] use Format in more places --- frontend/src/ts/account/pb-tables.ts | 3 - frontend/src/ts/elements/leaderboards.ts | 41 +++--- frontend/src/ts/elements/modes-notice.ts | 40 +++--- frontend/src/ts/pages/account.ts | 162 +++++------------------ frontend/src/ts/test/live-burst.ts | 9 +- frontend/src/ts/test/live-wpm.ts | 10 +- frontend/src/ts/test/result.ts | 1 + frontend/src/ts/test/test-ui.ts | 6 +- 8 files changed, 84 insertions(+), 188 deletions(-) diff --git a/frontend/src/ts/account/pb-tables.ts b/frontend/src/ts/account/pb-tables.ts index 97552d7b0167..d0159319d44a 100644 --- a/frontend/src/ts/account/pb-tables.ts +++ b/frontend/src/ts/account/pb-tables.ts @@ -1,7 +1,5 @@ import Config from "../config"; import format from "date-fns/format"; -import * as Misc from "../utils/misc"; -import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; import * as Format from "../utils/format"; function clearTables(isProfile: boolean): void { @@ -141,7 +139,6 @@ function buildPbHtml( let dateText = ""; const modeString = `${mode2} ${mode === "time" ? "seconds" : "words"}`; const speedUnit = Config.typingSpeedUnit; - const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit); try { const pbData = (pbs[mode][mode2] ?? []).sort((a, b) => b.wpm - a.wpm)[0]; diff --git a/frontend/src/ts/elements/leaderboards.ts b/frontend/src/ts/elements/leaderboards.ts index b37b9b8f47a1..ac0a7e1af6c7 100644 --- a/frontend/src/ts/elements/leaderboards.ts +++ b/frontend/src/ts/elements/leaderboards.ts @@ -2,7 +2,6 @@ import Ape from "../ape"; import * as DB from "../db"; import Config from "../config"; import * as Misc from "../utils/misc"; -import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; import * as Notifications from "./notifications"; import format from "date-fns/format"; import { isAuthenticated } from "../firebase"; @@ -11,6 +10,7 @@ import { getHTMLById as getBadgeHTMLbyId } from "../controllers/badge-controller import * as ConnectionState from "../states/connection"; import * as Skeleton from "../popups/skeleton"; import { debounce } from "throttle-debounce"; +import * as Format from "../utils/format"; const wrapperId = "leaderboardsWrapper"; @@ -164,7 +164,6 @@ function updateFooter(lb: LbKey): void { return; } - const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit); if (DB.getSnapshot()?.lbOptOut === true) { $(`#leaderboardsWrapper table.${side} tfoot`).html(` @@ -210,12 +209,18 @@ function updateFooter(lb: LbKey): void { ${lbRank.rank} You${toppercent ? toppercent : ""} - ${typingSpeedUnit.fromWpm(entry.wpm).toFixed(2)}
-
${entry.acc.toFixed(2)}%
- ${typingSpeedUnit.fromWpm(entry.raw).toFixed(2)}
-
${ - entry.consistency === undefined ? "-" : entry.consistency.toFixed(2) + "%" - }
+ ${Format.typingSpeed(entry.wpm, { + showDecimalPlaces: true, + })}
+
${Format.percentage(entry.acc, { + showDecimalPlaces: true, + })}%
+ ${Format.typingSpeed(entry.raw, { + showDecimalPlaces: true, + })}
+
${Format.percentage(entry.consistency, { + showDecimalPlaces: true, + })}
${format(date, "dd MMM yyyy")}
${format(date, "HH:mm")}
@@ -295,8 +300,6 @@ async function fillTable(lb: LbKey): Promise { "No results found" ); } - - const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit); const loggedInUserName = DB.getSnapshot()?.name; let html = ""; @@ -335,12 +338,18 @@ async function fillTable(lb: LbKey): Promise { ${entry.badgeId ? getBadgeHTMLbyId(entry.badgeId) : ""} - ${typingSpeedUnit.fromWpm(entry.wpm).toFixed(2)}
-
${entry.acc.toFixed(2)}%
- ${typingSpeedUnit.fromWpm(entry.raw).toFixed(2)}
-
${ - entry.consistency === undefined ? "-" : entry.consistency.toFixed(2) + "%" - }
+ ${Format.typingSpeed(entry.wpm, { + showDecimalPlaces: true, + })}
+
${Format.percentage(entry.acc, { + showDecimalPlaces: true, + })}
+ ${Format.typingSpeed(entry.raw, { + showDecimalPlaces: true, + })}
+
${Format.percentage(entry.consistency, { + showDecimalPlaces: true, + })}
${format(date, "dd MMM yyyy")}
${format(date, "HH:mm")}
diff --git a/frontend/src/ts/elements/modes-notice.ts b/frontend/src/ts/elements/modes-notice.ts index d813172e6c9c..14b00341580d 100644 --- a/frontend/src/ts/elements/modes-notice.ts +++ b/frontend/src/ts/elements/modes-notice.ts @@ -7,8 +7,8 @@ import * as TestWords from "../test/test-words"; import * as ConfigEvent from "../observables/config-event"; import { isAuthenticated } from "../firebase"; import * as CustomTextState from "../states/custom-text-name"; -import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; -import { getLanguageDisplayString, roundTo2 } from "../utils/misc"; +import { getLanguageDisplayString } from "../utils/misc"; +import * as Format from "../utils/format"; ConfigEvent.subscribe((eventKey) => { if ( @@ -123,14 +123,11 @@ export async function update(): Promise { Config.paceCaret !== "off" || (Config.repeatedPace && TestState.isPaceRepeat) ) { - let speed = ""; - try { - speed = ` (${roundTo2( - getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm( - PaceCaret.settings?.wpm ?? 0 - ) - )} ${Config.typingSpeedUnit})`; - } catch {} + const speed = Format.typingSpeed(PaceCaret.settings?.wpm ?? 0, { + showDecimalPlaces: true, + suffix: ` ${Config.typingSpeedUnit}`, + }); + $(".pageTest #testModesNotice").append( `
${ Config.paceCaret === "average" @@ -142,7 +139,7 @@ export async function update(): Promise { : Config.paceCaret === "daily" ? "daily" : "custom" - } pace${speed}
` + } pace ${speed}` ); } @@ -157,10 +154,7 @@ export async function update(): Promise { if (isAuthenticated() && avgWPM > 0) { const avgWPMText = ["speed", "both"].includes(Config.showAverage) - ? getTypingSpeedUnit(Config.typingSpeedUnit).convertWithUnitSuffix( - avgWPM, - Config.alwaysShowDecimalPlaces - ) + ? Format.typingSpeed(avgWPM) : ""; const avgAccText = ["acc", "both"].includes(Config.showAverage) @@ -177,11 +171,10 @@ export async function update(): Promise { if (Config.minWpm !== "off") { $(".pageTest #testModesNotice").append( - `
min ${roundTo2( - getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm( - Config.minWpmCustomSpeed - ) - )} ${Config.typingSpeedUnit}
` + `
min ${Format.typingSpeed( + Config.minWpmCustomSpeed, + { showDecimalPlaces: true, suffix: ` ${Config.typingSpeedUnit}` } + )}
` ); } @@ -193,10 +186,9 @@ export async function update(): Promise { if (Config.minBurst !== "off") { $(".pageTest #testModesNotice").append( - `
min ${roundTo2( - getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm( - Config.minBurstCustomSpeed - ) + `
min ${Format.typingSpeed( + Config.minBurstCustomSpeed, + { showDecimalPlaces: true } )} ${Config.typingSpeedUnit} burst ${ Config.minBurst === "flex" ? "(flex)" : "" }
` diff --git a/frontend/src/ts/pages/account.ts b/frontend/src/ts/pages/account.ts index aed4c4e14bfe..8e1f7b186632 100644 --- a/frontend/src/ts/pages/account.ts +++ b/frontend/src/ts/pages/account.ts @@ -23,6 +23,7 @@ import * as ActivePage from "../states/active-page"; import { Auth } from "../firebase"; import * as Loader from "../elements/loader"; import * as ResultBatches from "../elements/result-batches"; +import * as Format from "../utils/format"; let filterDebug = false; //toggle filterdebug @@ -37,7 +38,6 @@ let filteredResults: SharedTypes.Result[] = []; let visibleTableLines = 0; function loadMoreLines(lineIndex?: number): void { - const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit); if (filteredResults === undefined || filteredResults.length === 0) return; let newVisibleLines; if (lineIndex && lineIndex > visibleTableLines) { @@ -53,16 +53,6 @@ function loadMoreLines(lineIndex?: number): void { diff = "normal"; } - let raw; - try { - raw = typingSpeedUnit.fromWpm(result.rawWpm).toFixed(2); - if (raw === undefined) { - raw = "-"; - } - } catch (e) { - raw = "-"; - } - let icons = ` ${pb} - ${typingSpeedUnit.fromWpm(result.wpm).toFixed(2)} - ${raw} - ${result.acc.toFixed(2)}% - ${consistency} + ${Format.typingSpeed(result.wpm, { showDecimalPlaces: true })} + ${Format.typingSpeed(result.rawWpm, { showDecimalPlaces: true })} + ${Format.percentage(result.acc, { showDecimalPlaces: true })} + ${Format.percentage(result.consistency, { + showDecimalPlaces: true, + })} ${charStats} ${result.mode} ${result.mode2} ${icons} @@ -860,144 +846,58 @@ async function fillContent(): Promise { Misc.secondsToString(Math.round(totalSecondsFiltered), true, true) ); - let highestSpeed: number | string = typingSpeedUnit.fromWpm(topWpm); - - if (Config.alwaysShowDecimalPlaces) { - highestSpeed = Misc.roundTo2(highestSpeed).toFixed(2); - } else { - highestSpeed = Math.round(highestSpeed); - } - const speedUnit = Config.typingSpeedUnit; $(".pageAccount .highestWpm .title").text(`highest ${speedUnit}`); - $(".pageAccount .highestWpm .val").text(highestSpeed); - - let averageSpeed: number | string = typingSpeedUnit.fromWpm(totalWpm); - if (Config.alwaysShowDecimalPlaces) { - averageSpeed = Misc.roundTo2(averageSpeed / testCount).toFixed(2); - } else { - averageSpeed = Math.round(averageSpeed / testCount); - } + $(".pageAccount .highestWpm .val").text(Format.typingSpeed(topWpm)); $(".pageAccount .averageWpm .title").text(`average ${speedUnit}`); - $(".pageAccount .averageWpm .val").text(averageSpeed); - - let averageSpeedLast10: number | string = - typingSpeedUnit.fromWpm(wpmLast10total); - if (Config.alwaysShowDecimalPlaces) { - averageSpeedLast10 = Misc.roundTo2(averageSpeedLast10 / last10).toFixed(2); - } else { - averageSpeedLast10 = Math.round(averageSpeedLast10 / last10); - } + $(".pageAccount .averageWpm .val").text( + Format.typingSpeed(totalWpm / testCount) + ); $(".pageAccount .averageWpm10 .title").text( `average ${speedUnit} (last 10 tests)` ); - $(".pageAccount .averageWpm10 .val").text(averageSpeedLast10); - - let highestRawSpeed: number | string = typingSpeedUnit.fromWpm(rawWpm.max); - if (Config.alwaysShowDecimalPlaces) { - highestRawSpeed = Misc.roundTo2(highestRawSpeed).toFixed(2); - } else { - highestRawSpeed = Math.round(highestRawSpeed); - } + $(".pageAccount .averageWpm10 .val").text( + Format.typingSpeed(wpmLast10total / last10) + ); $(".pageAccount .highestRaw .title").text(`highest raw ${speedUnit}`); - $(".pageAccount .highestRaw .val").text(highestRawSpeed); - - let averageRawSpeed: number | string = typingSpeedUnit.fromWpm(rawWpm.total); - if (Config.alwaysShowDecimalPlaces) { - averageRawSpeed = Misc.roundTo2(averageRawSpeed / rawWpm.count).toFixed(2); - } else { - averageRawSpeed = Math.round(averageRawSpeed / rawWpm.count); - } + $(".pageAccount .highestRaw .val").text(Format.typingSpeed(rawWpm.max)); $(".pageAccount .averageRaw .title").text(`average raw ${speedUnit}`); - $(".pageAccount .averageRaw .val").text(averageRawSpeed); - - let averageRawSpeedLast10: number | string = typingSpeedUnit.fromWpm( - rawWpm.last10Total + $(".pageAccount .averageRaw .val").text( + Format.typingSpeed(rawWpm.total / rawWpm.count) ); - if (Config.alwaysShowDecimalPlaces) { - averageRawSpeedLast10 = Misc.roundTo2( - averageRawSpeedLast10 / rawWpm.last10Count - ).toFixed(2); - } else { - averageRawSpeedLast10 = Math.round( - averageRawSpeedLast10 / rawWpm.last10Count - ); - } $(".pageAccount .averageRaw10 .title").text( `average raw ${speedUnit} (last 10 tests)` ); - $(".pageAccount .averageRaw10 .val").text(averageRawSpeedLast10); + $(".pageAccount .averageRaw10 .val").text( + Format.typingSpeed(rawWpm.last10Total / rawWpm.last10Count) + ); $(".pageAccount .highestWpm .mode").html(topMode); $(".pageAccount .testsTaken .val").text(testCount); - let highestAcc: string | number = topAcc; - if (Config.alwaysShowDecimalPlaces) { - highestAcc = Misc.roundTo2(highestAcc).toFixed(2); - } else { - highestAcc = Math.floor(highestAcc); - } - - $(".pageAccount .highestAcc .val").text(highestAcc + "%"); - - let averageAcc: number | string = totalAcc; - if (Config.alwaysShowDecimalPlaces) { - averageAcc = Misc.roundTo2(averageAcc / testCount); - } else { - averageAcc = Math.floor(averageAcc / testCount); - } - - $(".pageAccount .avgAcc .val").text(averageAcc + "%"); - - let averageAccLast10: number | string = totalAcc10; - if (Config.alwaysShowDecimalPlaces) { - averageAccLast10 = Misc.roundTo2(averageAccLast10 / last10); - } else { - averageAccLast10 = Math.floor(averageAccLast10 / last10); - } - - $(".pageAccount .avgAcc10 .val").text(averageAccLast10 + "%"); + $(".pageAccount .highestAcc .val").text(Format.percentage(topAcc)); + $(".pageAccount .avgAcc .val").text(Format.percentage(totalAcc / testCount)); + $(".pageAccount .avgAcc10 .val").text(Format.percentage(totalAcc10 / last10)); if (totalCons === 0 || totalCons === undefined) { $(".pageAccount .avgCons .val").text("-"); $(".pageAccount .avgCons10 .val").text("-"); } else { - let highestCons: number | string = topCons; - if (Config.alwaysShowDecimalPlaces) { - highestCons = Misc.roundTo2(highestCons).toFixed(2); - } else { - highestCons = Math.round(highestCons); - } - - $(".pageAccount .highestCons .val").text(highestCons + "%"); - - let averageCons: number | string = totalCons; - if (Config.alwaysShowDecimalPlaces) { - averageCons = Misc.roundTo2(averageCons / consCount).toFixed(2); - } else { - averageCons = Math.round(averageCons / consCount); - } + $(".pageAccount .highestCons .val").text(Format.percentage(topCons)); - $(".pageAccount .avgCons .val").text(averageCons + "%"); - - let averageConsLast10: number | string = totalCons10; - if (Config.alwaysShowDecimalPlaces) { - averageConsLast10 = Misc.roundTo2( - averageConsLast10 / Math.min(last10, consCount) - ).toFixed(2); - } else { - averageConsLast10 = Math.round( - averageConsLast10 / Math.min(last10, consCount) - ); - } + $(".pageAccount .avgCons .val").text( + Format.percentage(totalCons / consCount) + ); - $(".pageAccount .avgCons10 .val").text(averageConsLast10 + "%"); + $(".pageAccount .avgCons10 .val").text( + Format.percentage(totalCons10 / Math.min(last10, consCount)) + ); } $(".pageAccount .testsStarted .val").text(`${testCount + testRestarts}`); @@ -1020,7 +920,7 @@ async function fillContent(): Promise { const plus = wpmChangePerHour > 0 ? "+" : ""; $(".pageAccount .group.chart .below .text").text( `Speed change per hour spent typing: ${ - plus + Misc.roundTo2(typingSpeedUnit.fromWpm(wpmChangePerHour)) + plus + Format.typingSpeed(wpmChangePerHour, { showDecimalPlaces: true }) } ${Config.typingSpeedUnit}` ); } diff --git a/frontend/src/ts/test/live-burst.ts b/frontend/src/ts/test/live-burst.ts index 5fb88c28b449..1e99d6abe25e 100644 --- a/frontend/src/ts/test/live-burst.ts +++ b/frontend/src/ts/test/live-burst.ts @@ -1,15 +1,14 @@ import Config from "../config"; import * as TestState from "../test/test-state"; import * as ConfigEvent from "../observables/config-event"; -import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; +import * as Format from "../utils/format"; export async function update(burst: number): Promise { if (!Config.showLiveBurst) return; - burst = Math.round(getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm(burst)); + const burstText = Format.typingSpeed(burst, { showDecimalPlaces: false }); (document.querySelector("#miniTimerAndLiveWpm .burst") as Element).innerHTML = - burst.toString(); - (document.querySelector("#liveBurst") as Element).innerHTML = - burst.toString(); + burstText; + (document.querySelector("#liveBurst") as Element).innerHTML = burstText; } let state = false; diff --git a/frontend/src/ts/test/live-wpm.ts b/frontend/src/ts/test/live-wpm.ts index e36acb11a9d8..42825c57379c 100644 --- a/frontend/src/ts/test/live-wpm.ts +++ b/frontend/src/ts/test/live-wpm.ts @@ -1,7 +1,7 @@ import Config from "../config"; import * as TestState from "../test/test-state"; import * as ConfigEvent from "../observables/config-event"; -import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; +import * as Format from "../utils/format"; const liveWpmElement = document.querySelector("#liveWpm") as Element; const miniLiveWpmElement = document.querySelector( @@ -13,11 +13,9 @@ export function update(wpm: number, raw: number): void { if (Config.blindMode) { number = raw; } - number = Math.round( - getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm(number) - ); - miniLiveWpmElement.innerHTML = number.toString(); - liveWpmElement.innerHTML = number.toString(); + const numberText = Format.typingSpeed(number, { showDecimalPlaces: false }); + miniLiveWpmElement.innerHTML = numberText; + liveWpmElement.innerHTML = numberText; } let state = false; diff --git a/frontend/src/ts/test/result.ts b/frontend/src/ts/test/result.ts index cc6906164b42..196972aeffd3 100644 --- a/frontend/src/ts/test/result.ts +++ b/frontend/src/ts/test/result.ts @@ -1,3 +1,4 @@ +//TODO: use Format import { Chart, type PluginChartOptions } from "chart.js"; import Config from "../config"; import * as AdController from "../controllers/ad-controller"; diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts index 9a0aaac080ca..5976ce066e72 100644 --- a/frontend/src/ts/test/test-ui.ts +++ b/frontend/src/ts/test/test-ui.ts @@ -22,6 +22,7 @@ import { debounce } from "throttle-debounce"; import * as ResultWordHighlight from "../elements/result-word-highlight"; import * as ActivePage from "../states/active-page"; import html2canvas from "html2canvas"; +import * as Format from "../utils/format"; const debouncedZipfCheck = debounce(250, async () => { const supports = await Misc.checkIfLanguageSupportsZipf(Config.language); @@ -1299,9 +1300,8 @@ $(".pageTest #resultWordsHistory").on("mouseenter", ".words .word", (e) => { .replace(/>/g, ">")}
- ${Math.round( - getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm(burst) - )}${Config.typingSpeedUnit} + ${Format.typingSpeed(burst, { showDecimalPlaces: false })} + ${Config.typingSpeedUnit}
` ); From 652fe5ac2e0acaf745a865f7faa11b18e290f103 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Sat, 17 Feb 2024 23:06:06 +0100 Subject: [PATCH 06/11] Make config mockable --- frontend/__tests__/utils/format.spec.ts | 41 +++++++++++++------------ frontend/src/ts/config.ts | 3 ++ frontend/src/ts/utils/format.ts | 6 ++-- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/frontend/__tests__/utils/format.spec.ts b/frontend/__tests__/utils/format.spec.ts index c626043d11bd..2dcaa0b00e5d 100644 --- a/frontend/__tests__/utils/format.spec.ts +++ b/frontend/__tests__/utils/format.spec.ts @@ -1,36 +1,30 @@ import * as Format from "../../src/ts/utils/format"; -import Config from "../../src/ts/config"; - -const configMock: Partial = {}; +import * as MockConfig from "../../src/ts/config"; +import DefaultConfig from "../../src/ts/constants/default-config"; describe("format.ts", () => { - beforeEach(() => { - Config.typingSpeedUnit = "wpm"; - Config.alwaysShowDecimalPlaces = false; + afterEach(() => { + jest.resetAllMocks(); }); describe("typingsSpeed", () => { it("should format with typing speed and decimalPlaces from configuration", () => { //wpm, no decimals - Config.typingSpeedUnit = "wpm"; - Config.alwaysShowDecimalPlaces = false; + mockConfig({ typingSpeedUnit: "wpm", alwaysShowDecimalPlaces: false }); expect(Format.typingSpeed(12.5)).toEqual("13"); expect(Format.typingSpeed(0)).toEqual("0"); //cpm, no decimals - Config.typingSpeedUnit = "cpm"; - Config.alwaysShowDecimalPlaces = false; + mockConfig({ typingSpeedUnit: "cpm", alwaysShowDecimalPlaces: false }); expect(Format.typingSpeed(12.5)).toEqual("63"); expect(Format.typingSpeed(0)).toEqual("0"); //wpm, with decimals - Config.typingSpeedUnit = "wpm"; - Config.alwaysShowDecimalPlaces = true; + mockConfig({ typingSpeedUnit: "wpm", alwaysShowDecimalPlaces: true }); expect(Format.typingSpeed(12.5)).toEqual("12.50"); expect(Format.typingSpeed(0)).toEqual("0.00"); //cpm, with decimals - Config.typingSpeedUnit = "cpm"; - Config.alwaysShowDecimalPlaces = true; + mockConfig({ typingSpeedUnit: "cpm", alwaysShowDecimalPlaces: true }); expect(Format.typingSpeed(12.5)).toEqual("62.50"); expect(Format.typingSpeed(0)).toEqual("0.00"); }); @@ -55,18 +49,19 @@ describe("format.ts", () => { it("should format with decimals", () => { //force with decimals - Config.alwaysShowDecimalPlaces = false; + mockConfig({ typingSpeedUnit: "wpm", alwaysShowDecimalPlaces: false }); expect(Format.typingSpeed(100, { showDecimalPlaces: true })).toEqual( "100.00" ); //force without decimals - Config.alwaysShowDecimalPlaces = true; + mockConfig({ typingSpeedUnit: "wpm", alwaysShowDecimalPlaces: true }); expect(Format.typingSpeed(100, { showDecimalPlaces: false })).toEqual( "100" ); }); it("should format with suffix", () => { + mockConfig({ typingSpeedUnit: "wpm", alwaysShowDecimalPlaces: false }); expect(Format.typingSpeed(100, { suffix: " raw" })).toEqual("100 raw"); expect(Format.typingSpeed(100, { suffix: undefined })).toEqual("100"); expect(Format.typingSpeed(0, { suffix: " raw" })).toEqual("0 raw"); @@ -77,12 +72,12 @@ describe("format.ts", () => { describe("percentage", () => { it("should format with decimalPlaces from configuration", () => { //no decimals - Config.alwaysShowDecimalPlaces = false; + mockConfig({ alwaysShowDecimalPlaces: false }); expect(Format.percentage(12.5)).toEqual("13%"); expect(Format.percentage(0)).toEqual("0%"); //with decimals - Config.alwaysShowDecimalPlaces = true; + mockConfig({ alwaysShowDecimalPlaces: true }); expect(Format.percentage(12.5)).toEqual("12.50%"); expect(Format.percentage(0)).toEqual("0.00%"); }); @@ -105,18 +100,19 @@ describe("format.ts", () => { it("should format with decimals", () => { //force with decimals - Config.alwaysShowDecimalPlaces = false; + mockConfig({ alwaysShowDecimalPlaces: false }); expect(Format.percentage(100, { showDecimalPlaces: true })).toEqual( "100.00%" ); //force without decimals - Config.alwaysShowDecimalPlaces = true; + mockConfig({ alwaysShowDecimalPlaces: true }); expect(Format.percentage(100, { showDecimalPlaces: false })).toEqual( "100%" ); }); it("should format with suffix", () => { + mockConfig({ alwaysShowDecimalPlaces: false }); expect(Format.percentage(100, { suffix: " raw" })).toEqual("100% raw"); expect(Format.percentage(100, { suffix: undefined })).toEqual("100%"); expect(Format.percentage(0, { suffix: " raw" })).toEqual("0% raw"); @@ -125,3 +121,8 @@ describe("format.ts", () => { }); }); }); + +function mockConfig(config: Partial): void { + const target: SharedTypes.Config = { ...DefaultConfig, ...config }; + jest.spyOn(MockConfig, "getConfig").mockReturnValue(target); +} diff --git a/frontend/src/ts/config.ts b/frontend/src/ts/config.ts index 9f93316c9470..9b51e71e0829 100644 --- a/frontend/src/ts/config.ts +++ b/frontend/src/ts/config.ts @@ -2032,3 +2032,6 @@ export const loadPromise = new Promise((v) => { }); export default config; +export function getConfig(): SharedTypes.Config { + return config; +} diff --git a/frontend/src/ts/utils/format.ts b/frontend/src/ts/utils/format.ts index 7f7f4ed370c3..1f445fbd29a1 100644 --- a/frontend/src/ts/utils/format.ts +++ b/frontend/src/ts/utils/format.ts @@ -1,5 +1,5 @@ import * as Misc from "./misc"; -import Config from "../config"; +import { getConfig } from "../config"; import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; export type FormatOptions = { @@ -21,7 +21,7 @@ export function typingSpeed( const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions }; if (wpm === undefined || wpm === null) return options.fallback ?? ""; - const result = getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm(wpm); + const result = getTypingSpeedUnit(getConfig().typingSpeedUnit).fromWpm(wpm); return decimals(result, options); } @@ -47,7 +47,7 @@ function decimals( if ( formatOptions.showDecimalPlaces !== undefined ? formatOptions.showDecimalPlaces - : Config.alwaysShowDecimalPlaces + : getConfig().alwaysShowDecimalPlaces ) { return Misc.roundTo2(value).toFixed(2) + suffix; } From 7aa70ebebaaf5fffa95ce58682895e45930ab5c9 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Sun, 18 Feb 2024 15:04:09 +0100 Subject: [PATCH 07/11] dependency injection --- frontend/__tests__/utils/format.spec.ts | 145 ++++++++++++++---------- frontend/src/ts/account/pb-tables.ts | 14 ++- frontend/src/ts/config.ts | 3 - frontend/src/ts/utils/format.ts | 73 ++++++------ 4 files changed, 132 insertions(+), 103 deletions(-) diff --git a/frontend/__tests__/utils/format.spec.ts b/frontend/__tests__/utils/format.spec.ts index 2dcaa0b00e5d..e09631e74246 100644 --- a/frontend/__tests__/utils/format.spec.ts +++ b/frontend/__tests__/utils/format.spec.ts @@ -1,4 +1,4 @@ -import * as Format from "../../src/ts/utils/format"; +import { Formatting } from "../../src/ts/utils/format"; import * as MockConfig from "../../src/ts/config"; import DefaultConfig from "../../src/ts/constants/default-config"; @@ -9,120 +9,143 @@ describe("format.ts", () => { describe("typingsSpeed", () => { it("should format with typing speed and decimalPlaces from configuration", () => { //wpm, no decimals - mockConfig({ typingSpeedUnit: "wpm", alwaysShowDecimalPlaces: false }); - expect(Format.typingSpeed(12.5)).toEqual("13"); - expect(Format.typingSpeed(0)).toEqual("0"); + const wpmNoDecimals = getInstance({ + typingSpeedUnit: "wpm", + alwaysShowDecimalPlaces: false, + }); + expect(wpmNoDecimals.typingSpeed(12.5)).toEqual("13"); + expect(wpmNoDecimals.typingSpeed(0)).toEqual("0"); //cpm, no decimals - mockConfig({ typingSpeedUnit: "cpm", alwaysShowDecimalPlaces: false }); - expect(Format.typingSpeed(12.5)).toEqual("63"); - expect(Format.typingSpeed(0)).toEqual("0"); + const cpmNoDecimals = getInstance({ + typingSpeedUnit: "cpm", + alwaysShowDecimalPlaces: false, + }); + expect(cpmNoDecimals.typingSpeed(12.5)).toEqual("63"); + expect(cpmNoDecimals.typingSpeed(0)).toEqual("0"); //wpm, with decimals - mockConfig({ typingSpeedUnit: "wpm", alwaysShowDecimalPlaces: true }); - expect(Format.typingSpeed(12.5)).toEqual("12.50"); - expect(Format.typingSpeed(0)).toEqual("0.00"); + const wpmWithDecimals = getInstance({ + typingSpeedUnit: "wpm", + alwaysShowDecimalPlaces: true, + }); + expect(wpmWithDecimals.typingSpeed(12.5)).toEqual("12.50"); + expect(wpmWithDecimals.typingSpeed(0)).toEqual("0.00"); //cpm, with decimals - mockConfig({ typingSpeedUnit: "cpm", alwaysShowDecimalPlaces: true }); - expect(Format.typingSpeed(12.5)).toEqual("62.50"); - expect(Format.typingSpeed(0)).toEqual("0.00"); + const cpmWithDecimals = getInstance({ + typingSpeedUnit: "cpm", + alwaysShowDecimalPlaces: true, + }); + expect(cpmWithDecimals.typingSpeed(12.5)).toEqual("62.50"); + expect(cpmWithDecimals.typingSpeed(0)).toEqual("0.00"); }); it("should format with fallback", () => { //default fallback - expect(Format.typingSpeed(null)).toEqual("-"); - expect(Format.typingSpeed(undefined)).toEqual("-"); + const format = getInstance(); + expect(format.typingSpeed(null)).toEqual("-"); + expect(format.typingSpeed(undefined)).toEqual("-"); //provided fallback - expect(Format.typingSpeed(null, { fallback: "none" })).toEqual("none"); - expect(Format.typingSpeed(null, { fallback: "" })).toEqual(""); - expect(Format.typingSpeed(undefined, { fallback: "none" })).toEqual( + expect(format.typingSpeed(null, { fallback: "none" })).toEqual("none"); + expect(format.typingSpeed(null, { fallback: "" })).toEqual(""); + expect(format.typingSpeed(undefined, { fallback: "none" })).toEqual( "none" ); - expect(Format.typingSpeed(undefined, { fallback: "" })).toEqual(""); - expect(Format.typingSpeed(undefined, { fallback: undefined })).toEqual( + expect(format.typingSpeed(undefined, { fallback: "" })).toEqual(""); + expect(format.typingSpeed(undefined, { fallback: undefined })).toEqual( "" ); }); it("should format with decimals", () => { //force with decimals - mockConfig({ typingSpeedUnit: "wpm", alwaysShowDecimalPlaces: false }); - expect(Format.typingSpeed(100, { showDecimalPlaces: true })).toEqual( - "100.00" - ); + const wpmNoDecimals = getInstance({ + typingSpeedUnit: "wpm", + alwaysShowDecimalPlaces: false, + }); + expect( + wpmNoDecimals.typingSpeed(100, { showDecimalPlaces: true }) + ).toEqual("100.00"); //force without decimals - mockConfig({ typingSpeedUnit: "wpm", alwaysShowDecimalPlaces: true }); - expect(Format.typingSpeed(100, { showDecimalPlaces: false })).toEqual( - "100" - ); + const wpmWithDecimals = getInstance({ + typingSpeedUnit: "wpm", + alwaysShowDecimalPlaces: true, + }); + expect( + wpmWithDecimals.typingSpeed(100, { showDecimalPlaces: false }) + ).toEqual("100"); }); it("should format with suffix", () => { - mockConfig({ typingSpeedUnit: "wpm", alwaysShowDecimalPlaces: false }); - expect(Format.typingSpeed(100, { suffix: " raw" })).toEqual("100 raw"); - expect(Format.typingSpeed(100, { suffix: undefined })).toEqual("100"); - expect(Format.typingSpeed(0, { suffix: " raw" })).toEqual("0 raw"); - expect(Format.typingSpeed(null, { suffix: " raw" })).toEqual("-"); - expect(Format.typingSpeed(undefined, { suffix: " raw" })).toEqual("-"); + const format = getInstance({ + typingSpeedUnit: "wpm", + alwaysShowDecimalPlaces: false, + }); + expect(format.typingSpeed(100, { suffix: " raw" })).toEqual("100 raw"); + expect(format.typingSpeed(100, { suffix: undefined })).toEqual("100"); + expect(format.typingSpeed(0, { suffix: " raw" })).toEqual("0 raw"); + expect(format.typingSpeed(null, { suffix: " raw" })).toEqual("-"); + expect(format.typingSpeed(undefined, { suffix: " raw" })).toEqual("-"); }); }); describe("percentage", () => { it("should format with decimalPlaces from configuration", () => { //no decimals - mockConfig({ alwaysShowDecimalPlaces: false }); - expect(Format.percentage(12.5)).toEqual("13%"); - expect(Format.percentage(0)).toEqual("0%"); + const noDecimals = getInstance({ alwaysShowDecimalPlaces: false }); + expect(noDecimals.percentage(12.5)).toEqual("13%"); + expect(noDecimals.percentage(0)).toEqual("0%"); //with decimals - mockConfig({ alwaysShowDecimalPlaces: true }); - expect(Format.percentage(12.5)).toEqual("12.50%"); - expect(Format.percentage(0)).toEqual("0.00%"); + const withDecimals = getInstance({ alwaysShowDecimalPlaces: true }); + expect(withDecimals.percentage(12.5)).toEqual("12.50%"); + expect(withDecimals.percentage(0)).toEqual("0.00%"); }); it("should format with fallback", () => { //default fallback - expect(Format.percentage(null)).toEqual("-"); - expect(Format.percentage(undefined)).toEqual("-"); + const format = getInstance(); + expect(format.percentage(null)).toEqual("-"); + expect(format.percentage(undefined)).toEqual("-"); //provided fallback - expect(Format.percentage(null, { fallback: "none" })).toEqual("none"); - expect(Format.percentage(null, { fallback: "" })).toEqual(""); - expect(Format.percentage(undefined, { fallback: "none" })).toEqual( + expect(format.percentage(null, { fallback: "none" })).toEqual("none"); + expect(format.percentage(null, { fallback: "" })).toEqual(""); + expect(format.percentage(undefined, { fallback: "none" })).toEqual( "none" ); - expect(Format.percentage(undefined, { fallback: "" })).toEqual(""); - expect(Format.percentage(undefined, { fallback: undefined })).toEqual(""); + expect(format.percentage(undefined, { fallback: "" })).toEqual(""); + expect(format.percentage(undefined, { fallback: undefined })).toEqual(""); }); it("should format with decimals", () => { //force with decimals - mockConfig({ alwaysShowDecimalPlaces: false }); - expect(Format.percentage(100, { showDecimalPlaces: true })).toEqual( + const noDecimals = getInstance({ alwaysShowDecimalPlaces: false }); + expect(noDecimals.percentage(100, { showDecimalPlaces: true })).toEqual( "100.00%" ); //force without decimals - mockConfig({ alwaysShowDecimalPlaces: true }); - expect(Format.percentage(100, { showDecimalPlaces: false })).toEqual( - "100%" - ); + const withDecimals = getInstance({ alwaysShowDecimalPlaces: true }); + expect( + withDecimals.percentage(100, { showDecimalPlaces: false }) + ).toEqual("100%"); }); it("should format with suffix", () => { - mockConfig({ alwaysShowDecimalPlaces: false }); - expect(Format.percentage(100, { suffix: " raw" })).toEqual("100% raw"); - expect(Format.percentage(100, { suffix: undefined })).toEqual("100%"); - expect(Format.percentage(0, { suffix: " raw" })).toEqual("0% raw"); - expect(Format.percentage(null, { suffix: " raw" })).toEqual("-"); - expect(Format.percentage(undefined, { suffix: " raw" })).toEqual("-"); + const format = getInstance({ alwaysShowDecimalPlaces: false }); + expect(format.percentage(100, { suffix: " raw" })).toEqual("100% raw"); + expect(format.percentage(100, { suffix: undefined })).toEqual("100%"); + expect(format.percentage(0, { suffix: " raw" })).toEqual("0% raw"); + expect(format.percentage(null, { suffix: " raw" })).toEqual("-"); + expect(format.percentage(undefined, { suffix: " raw" })).toEqual("-"); }); }); }); -function mockConfig(config: Partial): void { +function getInstance(config?: Partial): Formatting { const target: SharedTypes.Config = { ...DefaultConfig, ...config }; - jest.spyOn(MockConfig, "getConfig").mockReturnValue(target); + return new Formatting(target); } diff --git a/frontend/src/ts/account/pb-tables.ts b/frontend/src/ts/account/pb-tables.ts index d0159319d44a..4f1bcf0d67fd 100644 --- a/frontend/src/ts/account/pb-tables.ts +++ b/frontend/src/ts/account/pb-tables.ts @@ -1,6 +1,6 @@ import Config from "../config"; -import format from "date-fns/format"; -import * as Format from "../utils/format"; +import dateFormat from "date-fns/format"; +import Format from "../utils/format"; function clearTables(isProfile: boolean): void { const source = isProfile ? "Profile" : "Account"; @@ -146,7 +146,7 @@ function buildPbHtml( const date = new Date(pbData.timestamp); if (pbData.timestamp) { - dateText = format(date, "dd MMM yyyy"); + dateText = dateFormat(date, "dd MMM yyyy"); } retval = `
@@ -160,10 +160,14 @@ function buildPbHtml(
${modeString}
-
${Format.typingSpeed(pbData.wpm, { suffix: ` ${speedUnit}` })}
+
${Format.typingSpeed(pbData.wpm, { + suffix: ` ${speedUnit}`, + })}
${Format.typingSpeed(pbData.raw, { suffix: " raw" })}
${Format.percentage(pbData.acc, { suffix: " acc" })}
-
${Format.percentage(pbData.consistency, { suffix: " con" })}
+
${Format.percentage(pbData.consistency, { + suffix: " con", + })}
${dateText}
`; } catch (e) { diff --git a/frontend/src/ts/config.ts b/frontend/src/ts/config.ts index 9b51e71e0829..9f93316c9470 100644 --- a/frontend/src/ts/config.ts +++ b/frontend/src/ts/config.ts @@ -2032,6 +2032,3 @@ export const loadPromise = new Promise((v) => { }); export default config; -export function getConfig(): SharedTypes.Config { - return config; -} diff --git a/frontend/src/ts/utils/format.ts b/frontend/src/ts/utils/format.ts index 1f445fbd29a1..100deecee13b 100644 --- a/frontend/src/ts/utils/format.ts +++ b/frontend/src/ts/utils/format.ts @@ -1,5 +1,5 @@ import * as Misc from "./misc"; -import { getConfig } from "../config"; +import Config from "../config"; import { get as getTypingSpeedUnit } from "../utils/typing-speed-units"; export type FormatOptions = { @@ -14,42 +14,47 @@ const FORMAT_DEFAULT_OPTIONS: FormatOptions = { showDecimalPlaces: undefined, }; -export function typingSpeed( - wpm: number | null | undefined, - formatOptions: FormatOptions = FORMAT_DEFAULT_OPTIONS -): string { - const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions }; - if (wpm === undefined || wpm === null) return options.fallback ?? ""; +export class Formatting { + constructor(private config: SharedTypes.Config) {} - const result = getTypingSpeedUnit(getConfig().typingSpeedUnit).fromWpm(wpm); + typingSpeed( + wpm: number | null | undefined, + formatOptions: FormatOptions = FORMAT_DEFAULT_OPTIONS + ): string { + const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions }; + if (wpm === undefined || wpm === null) return options.fallback ?? ""; - return decimals(result, options); -} - -export function percentage( - percentage: number | null | undefined, - formatOptions: FormatOptions = FORMAT_DEFAULT_OPTIONS -): string { - const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions }; - options.suffix = "%" + (options.suffix ?? ""); + const result = getTypingSpeedUnit(this.config.typingSpeedUnit).fromWpm(wpm); - return decimals(percentage, options); -} + return this.decimals(result, options); + } + percentage( + percentage: number | null | undefined, + formatOptions: FormatOptions = FORMAT_DEFAULT_OPTIONS + ): string { + const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions }; + options.suffix = "%" + (options.suffix ?? ""); + + return this.decimals(percentage, options); + } -function decimals( - value: number | null | undefined, - formatOptions: FormatOptions -): string { - if (value === undefined || value === null) - return formatOptions.fallback ?? ""; - const suffix = formatOptions.suffix ?? ""; - - if ( - formatOptions.showDecimalPlaces !== undefined - ? formatOptions.showDecimalPlaces - : getConfig().alwaysShowDecimalPlaces - ) { - return Misc.roundTo2(value).toFixed(2) + suffix; + decimals( + value: number | null | undefined, + formatOptions: FormatOptions + ): string { + if (value === undefined || value === null) + return formatOptions.fallback ?? ""; + const suffix = formatOptions.suffix ?? ""; + + if ( + formatOptions.showDecimalPlaces !== undefined + ? formatOptions.showDecimalPlaces + : this.config.alwaysShowDecimalPlaces + ) { + return Misc.roundTo2(value).toFixed(2) + suffix; + } + return Math.round(value).toString() + suffix; } - return Math.round(value).toString() + suffix; } + +export default new Formatting(Config); From aa822fd0dcae8823c80a4e98c5f204f415f47375 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Mon, 19 Feb 2024 10:19:03 +0100 Subject: [PATCH 08/11] wip --- frontend/src/ts/elements/leaderboards.ts | 2 +- frontend/src/ts/elements/modes-notice.ts | 6 +-- frontend/src/ts/pages/account.ts | 2 +- frontend/src/ts/popups/pb-tables-popup.ts | 2 +- frontend/src/ts/test/live-burst.ts | 2 +- frontend/src/ts/test/live-wpm.ts | 2 +- frontend/src/ts/test/result.ts | 57 ++++++++++++--------- frontend/src/ts/test/test-ui.ts | 2 +- frontend/src/ts/types/types.d.ts | 1 - frontend/src/ts/utils/format.ts | 2 +- frontend/src/ts/utils/typing-speed-units.ts | 10 ---- 11 files changed, 43 insertions(+), 45 deletions(-) diff --git a/frontend/src/ts/elements/leaderboards.ts b/frontend/src/ts/elements/leaderboards.ts index ac0a7e1af6c7..2a1df73158d3 100644 --- a/frontend/src/ts/elements/leaderboards.ts +++ b/frontend/src/ts/elements/leaderboards.ts @@ -10,7 +10,7 @@ import { getHTMLById as getBadgeHTMLbyId } from "../controllers/badge-controller import * as ConnectionState from "../states/connection"; import * as Skeleton from "../popups/skeleton"; import { debounce } from "throttle-debounce"; -import * as Format from "../utils/format"; +import Format from "../utils/format"; const wrapperId = "leaderboardsWrapper"; diff --git a/frontend/src/ts/elements/modes-notice.ts b/frontend/src/ts/elements/modes-notice.ts index 14b00341580d..75fb6bcdf374 100644 --- a/frontend/src/ts/elements/modes-notice.ts +++ b/frontend/src/ts/elements/modes-notice.ts @@ -8,7 +8,7 @@ import * as ConfigEvent from "../observables/config-event"; import { isAuthenticated } from "../firebase"; import * as CustomTextState from "../states/custom-text-name"; import { getLanguageDisplayString } from "../utils/misc"; -import * as Format from "../utils/format"; +import Format from "../utils/format"; ConfigEvent.subscribe((eventKey) => { if ( @@ -154,11 +154,11 @@ export async function update(): Promise { if (isAuthenticated() && avgWPM > 0) { const avgWPMText = ["speed", "both"].includes(Config.showAverage) - ? Format.typingSpeed(avgWPM) + ? Format.typingSpeed(avgWPM, { suffix: ` ${Config.typingSpeedUnit}` }) : ""; const avgAccText = ["acc", "both"].includes(Config.showAverage) - ? `${avgAcc}% acc` + ? Format.percentage(avgAcc, { suffix: " acc" }) : ""; const text = `${avgWPMText} ${avgAccText}`.trim(); diff --git a/frontend/src/ts/pages/account.ts b/frontend/src/ts/pages/account.ts index 8e1f7b186632..f524bfb2e9c7 100644 --- a/frontend/src/ts/pages/account.ts +++ b/frontend/src/ts/pages/account.ts @@ -23,7 +23,7 @@ import * as ActivePage from "../states/active-page"; import { Auth } from "../firebase"; import * as Loader from "../elements/loader"; import * as ResultBatches from "../elements/result-batches"; -import * as Format from "../utils/format"; +import Format from "../utils/format"; let filterDebug = false; //toggle filterdebug diff --git a/frontend/src/ts/popups/pb-tables-popup.ts b/frontend/src/ts/popups/pb-tables-popup.ts index b0b69da0bea2..c85e1baa915c 100644 --- a/frontend/src/ts/popups/pb-tables-popup.ts +++ b/frontend/src/ts/popups/pb-tables-popup.ts @@ -3,7 +3,7 @@ import format from "date-fns/format"; import * as Skeleton from "./skeleton"; import { getLanguageDisplayString, isPopupVisible } from "../utils/misc"; import Config from "../config"; -import * as Format from "../utils/format"; +import Format from "../utils/format"; type PersonalBest = { mode2: SharedTypes.Config.Mode2; diff --git a/frontend/src/ts/test/live-burst.ts b/frontend/src/ts/test/live-burst.ts index 1e99d6abe25e..0387e7e48cbb 100644 --- a/frontend/src/ts/test/live-burst.ts +++ b/frontend/src/ts/test/live-burst.ts @@ -1,7 +1,7 @@ import Config from "../config"; import * as TestState from "../test/test-state"; import * as ConfigEvent from "../observables/config-event"; -import * as Format from "../utils/format"; +import Format from "../utils/format"; export async function update(burst: number): Promise { if (!Config.showLiveBurst) return; diff --git a/frontend/src/ts/test/live-wpm.ts b/frontend/src/ts/test/live-wpm.ts index 42825c57379c..a68106e64a84 100644 --- a/frontend/src/ts/test/live-wpm.ts +++ b/frontend/src/ts/test/live-wpm.ts @@ -1,7 +1,7 @@ import Config from "../config"; import * as TestState from "../test/test-state"; import * as ConfigEvent from "../observables/config-event"; -import * as Format from "../utils/format"; +import Format from "../utils/format"; const liveWpmElement = document.querySelector("#liveWpm") as Element; const miniLiveWpmElement = document.querySelector( diff --git a/frontend/src/ts/test/result.ts b/frontend/src/ts/test/result.ts index 196972aeffd3..2436221fa696 100644 --- a/frontend/src/ts/test/result.ts +++ b/frontend/src/ts/test/result.ts @@ -26,6 +26,7 @@ import * as Focus from "./focus"; import * as CustomText from "./custom-text"; import * as CustomTextState from "./../states/custom-text-name"; import * as Funbox from "./funbox/funbox"; +import Format from "../utils/format"; import confetti from "canvas-confetti"; import type { AnnotationOptions } from "chartjs-plugin-annotation"; @@ -214,7 +215,6 @@ export async function updateGraphPBLine(): Promise { function updateWpmAndAcc(): void { let inf = false; - const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit); if (result.wpm >= 1000) { inf = true; } @@ -225,11 +225,11 @@ function updateWpmAndAcc(): void { $("#result .stats .wpm .bottom").text("Infinite"); } else { $("#result .stats .wpm .bottom").text( - Misc.roundTo2(typingSpeedUnit.fromWpm(result.wpm)).toFixed(2) + Format.typingSpeed(result.wpm, { showDecimalPlaces: true }) ); } $("#result .stats .raw .bottom").text( - Misc.roundTo2(typingSpeedUnit.fromWpm(result.rawWpm)).toFixed(2) + Format.typingSpeed(result.rawWpm, { showDecimalPlaces: true }) ); if (Config.typingSpeedUnit != "wpm") { @@ -247,7 +247,9 @@ function updateWpmAndAcc(): void { } $("#result .stats .acc .bottom").text( - result.acc === 100 ? "100%" : Misc.roundTo2(result.acc).toFixed(2) + "%" + result.acc === 100 + ? "100%" + : Format.percentage(result.acc, { showDecimalPlaces: true }) ); let time = Misc.roundTo2(result.testDuration).toFixed(2) + "s"; if (result.testDuration > 61) { @@ -262,11 +264,13 @@ function updateWpmAndAcc(): void { ); } else { //not showing decimal places - let wpmHover = typingSpeedUnit.convertWithUnitSuffix(result.wpm, true); - let rawWpmHover = typingSpeedUnit.convertWithUnitSuffix( - result.rawWpm, - true - ); + const decimalsAndSuffix = { + showDecimalPlaces: true, + suffix: ` ${Config.typingSpeedUnit}`, + }; + let wpmHover = Format.typingSpeed(result.wpm, decimalsAndSuffix); + let rawWpmHover = Format.typingSpeed(result.rawWpm, decimalsAndSuffix); + if (Config.typingSpeedUnit != "wpm") { wpmHover += " (" + result.wpm.toFixed(2) + " wpm)"; rawWpmHover += " (" + result.rawWpm.toFixed(2) + " wpm)"; @@ -278,37 +282,43 @@ function updateWpmAndAcc(): void { $("#result .stats .wpm .bottom").text("Infinite"); } else { $("#result .stats .wpm .bottom").text( - Math.round(typingSpeedUnit.fromWpm(result.wpm)) + Format.typingSpeed(result.wpm, { showDecimalPlaces: false }) ); } $("#result .stats .raw .bottom").text( - Math.round(typingSpeedUnit.fromWpm(result.rawWpm)) + Format.typingSpeed(result.rawWpm, { showDecimalPlaces: false }) ); $("#result .stats .raw .bottom").attr("aria-label", rawWpmHover); - $("#result .stats .acc .bottom").text(Math.floor(result.acc) + "%"); + $("#result .stats .acc .bottom").text( + Format.percentage(result.acc, { showDecimalPlaces: false }) + ); $("#result .stats .acc .bottom").attr( "aria-label", - `${result.acc === 100 ? "100" : Misc.roundTo2(result.acc).toFixed(2)}% (${ - TestInput.accuracy.correct - } correct / ${TestInput.accuracy.incorrect} incorrect)` + `${ + result.acc === 100 + ? "100" + : Format.percentage(result.acc, { showDecimalPlaces: true }) + } (${TestInput.accuracy.correct} correct / ${ + TestInput.accuracy.incorrect + } incorrect)` ); } } function updateConsistency(): void { + $("#result .stats .consistency .bottom").text( + Format.percentage(result.consistency) + ); if (Config.alwaysShowDecimalPlaces) { - $("#result .stats .consistency .bottom").text( - Misc.roundTo2(result.consistency).toFixed(2) + "%" - ); $("#result .stats .consistency .bottom").attr( "aria-label", - `${result.keyConsistency.toFixed(2)}% key` + Format.percentage(result.keyConsistency, { + showDecimalPlaces: true, + suffix: " key", + }) ); } else { - $("#result .stats .consistency .bottom").text( - Math.round(result.consistency) + "%" - ); $("#result .stats .consistency .bottom").attr( "aria-label", `${result.consistency}% (${result.keyConsistency}% key)` @@ -417,11 +427,10 @@ export async function updateCrown(): Promise { Config.lazyMode, Config.funbox ); - const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit); pbDiff = Math.abs(result.wpm - lpb); $("#result .stats .wpm .crown").attr( "aria-label", - "+" + Misc.roundTo2(typingSpeedUnit.fromWpm(pbDiff)) + "+" + Format.typingSpeed(pbDiff, { showDecimalPlaces: true }) ); } diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts index 5976ce066e72..794f14aa9ae4 100644 --- a/frontend/src/ts/test/test-ui.ts +++ b/frontend/src/ts/test/test-ui.ts @@ -22,7 +22,7 @@ import { debounce } from "throttle-debounce"; import * as ResultWordHighlight from "../elements/result-word-highlight"; import * as ActivePage from "../states/active-page"; import html2canvas from "html2canvas"; -import * as Format from "../utils/format"; +import Format from "../utils/format"; const debouncedZipfCheck = debounce(250, async () => { const supports = await Misc.checkIfLanguageSupportsZipf(Config.language); diff --git a/frontend/src/ts/types/types.d.ts b/frontend/src/ts/types/types.d.ts index b6bc9b98ec28..3f7bed23ef2f 100644 --- a/frontend/src/ts/types/types.d.ts +++ b/frontend/src/ts/types/types.d.ts @@ -460,7 +460,6 @@ declare namespace MonkeyTypes { type TypingSpeedUnitSettings = { fromWpm: (number: number) => number; toWpm: (number: number) => number; - convertWithUnitSuffix: (number: number, withDecimals: boolean) => string; fullUnitString: string; histogramDataBucketSize: number; historyStepSize: number; diff --git a/frontend/src/ts/utils/format.ts b/frontend/src/ts/utils/format.ts index 100deecee13b..edfa2514f4e8 100644 --- a/frontend/src/ts/utils/format.ts +++ b/frontend/src/ts/utils/format.ts @@ -38,7 +38,7 @@ export class Formatting { return this.decimals(percentage, options); } - decimals( + private decimals( value: number | null | undefined, formatOptions: FormatOptions ): string { diff --git a/frontend/src/ts/utils/typing-speed-units.ts b/frontend/src/ts/utils/typing-speed-units.ts index 1e031ddd5796..c31b97f7c623 100644 --- a/frontend/src/ts/utils/typing-speed-units.ts +++ b/frontend/src/ts/utils/typing-speed-units.ts @@ -1,5 +1,3 @@ -import { roundTo2 } from "../utils/misc"; - class Unit implements MonkeyTypes.TypingSpeedUnitSettings { unit: SharedTypes.Config.TypingSpeedUnit; convertFactor: number; @@ -28,14 +26,6 @@ class Unit implements MonkeyTypes.TypingSpeedUnitSettings { toWpm(val: number): number { return val / this.convertFactor; } - - convertWithUnitSuffix(wpm: number, withDecimals: boolean): string { - if (withDecimals) { - return roundTo2(this.fromWpm(wpm)).toFixed(2) + " " + this.unit; - } else { - return Math.round(this.fromWpm(wpm)) + " " + this.unit; - } - } } const typingSpeedUnits: Record = { From b5c31a97c579842303be2bbe139ac51b6c50c541 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Mon, 19 Feb 2024 10:43:41 +0100 Subject: [PATCH 09/11] fix --- frontend/src/ts/test/result.ts | 44 ++++++++++----------------------- frontend/src/ts/utils/format.ts | 15 ++++++++--- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/frontend/src/ts/test/result.ts b/frontend/src/ts/test/result.ts index 2436221fa696..0fe10e2970f1 100644 --- a/frontend/src/ts/test/result.ts +++ b/frontend/src/ts/test/result.ts @@ -219,19 +219,19 @@ function updateWpmAndAcc(): void { inf = true; } - if (Config.alwaysShowDecimalPlaces) { - $("#result .stats .wpm .top .text").text(Config.typingSpeedUnit); - if (inf) { - $("#result .stats .wpm .bottom").text("Infinite"); - } else { - $("#result .stats .wpm .bottom").text( - Format.typingSpeed(result.wpm, { showDecimalPlaces: true }) - ); - } - $("#result .stats .raw .bottom").text( - Format.typingSpeed(result.rawWpm, { showDecimalPlaces: true }) - ); + $("#result .stats .wpm .top .text").text(Config.typingSpeedUnit); + + if (inf) { + $("#result .stats .wpm .bottom").text("Infinite"); + } else { + $("#result .stats .wpm .bottom").text(Format.typingSpeed(result.wpm)); + } + $("#result .stats .raw .bottom").text(Format.typingSpeed(result.rawWpm)); + $("#result .stats .acc .bottom").text( + result.acc === 100 ? "100%" : Format.percentage(result.acc) + ); + if (Config.alwaysShowDecimalPlaces) { if (Config.typingSpeedUnit != "wpm") { $("#result .stats .wpm .bottom").attr( "aria-label", @@ -246,11 +246,6 @@ function updateWpmAndAcc(): void { $("#result .stats .raw .bottom").removeAttr("aria-label"); } - $("#result .stats .acc .bottom").text( - result.acc === 100 - ? "100%" - : Format.percentage(result.acc, { showDecimalPlaces: true }) - ); let time = Misc.roundTo2(result.testDuration).toFixed(2) + "s"; if (result.testDuration > 61) { time = Misc.secondsToString(Misc.roundTo2(result.testDuration)); @@ -276,23 +271,9 @@ function updateWpmAndAcc(): void { rawWpmHover += " (" + result.rawWpm.toFixed(2) + " wpm)"; } - $("#result .stats .wpm .top .text").text(Config.typingSpeedUnit); $("#result .stats .wpm .bottom").attr("aria-label", wpmHover); - if (inf) { - $("#result .stats .wpm .bottom").text("Infinite"); - } else { - $("#result .stats .wpm .bottom").text( - Format.typingSpeed(result.wpm, { showDecimalPlaces: false }) - ); - } - $("#result .stats .raw .bottom").text( - Format.typingSpeed(result.rawWpm, { showDecimalPlaces: false }) - ); $("#result .stats .raw .bottom").attr("aria-label", rawWpmHover); - $("#result .stats .acc .bottom").text( - Format.percentage(result.acc, { showDecimalPlaces: false }) - ); $("#result .stats .acc .bottom").attr( "aria-label", `${ @@ -338,6 +319,7 @@ function updateTime(): void { "aria-label", `${result.afkDuration}s afk ${afkSecondsPercent}%` ); + if (Config.alwaysShowDecimalPlaces) { let time = Misc.roundTo2(result.testDuration).toFixed(2) + "s"; if (result.testDuration > 61) { diff --git a/frontend/src/ts/utils/format.ts b/frontend/src/ts/utils/format.ts index edfa2514f4e8..b9c63ae4a616 100644 --- a/frontend/src/ts/utils/format.ts +++ b/frontend/src/ts/utils/format.ts @@ -26,19 +26,26 @@ export class Formatting { const result = getTypingSpeedUnit(this.config.typingSpeedUnit).fromWpm(wpm); - return this.decimals(result, options); + return this.number(result, options); } percentage( percentage: number | null | undefined, - formatOptions: FormatOptions = FORMAT_DEFAULT_OPTIONS + formatOptions: FormatOptions = {} ): string { const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions }; options.suffix = "%" + (options.suffix ?? ""); - return this.decimals(percentage, options); + return this.number(percentage, options); } - private decimals( + decimals( + value: number | null | undefined, + formatOptions: FormatOptions = {} + ): string { + const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions }; + return this.number(value, options); + } + private number( value: number | null | undefined, formatOptions: FormatOptions ): string { From 7d4a3d308ca1cfa505813393a9721292aed9623d Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Mon, 19 Feb 2024 10:56:14 +0100 Subject: [PATCH 10/11] test --- frontend/__tests__/utils/format.spec.ts | 50 +++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/frontend/__tests__/utils/format.spec.ts b/frontend/__tests__/utils/format.spec.ts index e09631e74246..b7ebdd5cdbb5 100644 --- a/frontend/__tests__/utils/format.spec.ts +++ b/frontend/__tests__/utils/format.spec.ts @@ -143,6 +143,56 @@ describe("format.ts", () => { expect(format.percentage(undefined, { suffix: " raw" })).toEqual("-"); }); }); + describe("decimals", () => { + it("should format with decimalPlaces from configuration", () => { + //no decimals + const noDecimals = getInstance({ alwaysShowDecimalPlaces: false }); + expect(noDecimals.decimals(12.5)).toEqual("13"); + expect(noDecimals.decimals(0)).toEqual("0"); + + //with decimals + const withDecimals = getInstance({ alwaysShowDecimalPlaces: true }); + expect(withDecimals.decimals(12.5)).toEqual("12.50"); + expect(withDecimals.decimals(0)).toEqual("0.00"); + }); + + it("should format with fallback", () => { + //default fallback + const format = getInstance(); + expect(format.decimals(null)).toEqual("-"); + expect(format.decimals(undefined)).toEqual("-"); + + //provided fallback + expect(format.decimals(null, { fallback: "none" })).toEqual("none"); + expect(format.decimals(null, { fallback: "" })).toEqual(""); + expect(format.decimals(undefined, { fallback: "none" })).toEqual("none"); + + expect(format.decimals(undefined, { fallback: "" })).toEqual(""); + expect(format.decimals(undefined, { fallback: undefined })).toEqual(""); + }); + + it("should format with decimals", () => { + //force with decimals + const noDecimals = getInstance({ alwaysShowDecimalPlaces: false }); + expect(noDecimals.decimals(100, { showDecimalPlaces: true })).toEqual( + "100.00" + ); + //force without decimals + const withDecimals = getInstance({ alwaysShowDecimalPlaces: true }); + expect(withDecimals.decimals(100, { showDecimalPlaces: false })).toEqual( + "100" + ); + }); + + it("should format with suffix", () => { + const format = getInstance({ alwaysShowDecimalPlaces: false }); + expect(format.decimals(100, { suffix: " raw" })).toEqual("100 raw"); + expect(format.decimals(100, { suffix: undefined })).toEqual("100"); + expect(format.decimals(0, { suffix: " raw" })).toEqual("0 raw"); + expect(format.decimals(null, { suffix: " raw" })).toEqual("-"); + expect(format.decimals(undefined, { suffix: " raw" })).toEqual("-"); + }); + }); }); function getInstance(config?: Partial): Formatting { From a116d5eb86e2dd6bffc12c8e3e2ae404ae529f44 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Mon, 19 Feb 2024 11:00:03 +0100 Subject: [PATCH 11/11] touch