diff --git a/frontend/__tests__/utils/format.spec.ts b/frontend/__tests__/utils/format.spec.ts index cb324c2049ea..396aeac1754e 100644 --- a/frontend/__tests__/utils/format.spec.ts +++ b/frontend/__tests__/utils/format.spec.ts @@ -86,7 +86,15 @@ describe("format.ts", () => { expect(format.typingSpeed(null, { suffix: " raw" })).toEqual("-"); expect(format.typingSpeed(undefined, { suffix: " raw" })).toEqual("-"); }); + + it("should format with rounding", () => { + const format = getInstance({ alwaysShowDecimalPlaces: false }); + expect(format.typingSpeed(80.25)).toEqual("80"); + expect(format.typingSpeed(80.25, { rounding: Math.ceil })).toEqual("81"); + expect(format.typingSpeed(80.75, { rounding: Math.floor })).toEqual("80"); + }); }); + describe("percentage", () => { it("should format with decimalPlaces from configuration", () => { //no decimals @@ -138,7 +146,33 @@ describe("format.ts", () => { expect(format.percentage(null, { suffix: " raw" })).toEqual("-"); expect(format.percentage(undefined, { suffix: " raw" })).toEqual("-"); }); + + it("should format with rounding", () => { + const format = getInstance({ alwaysShowDecimalPlaces: false }); + expect(format.percentage(80.25)).toEqual("80%"); + expect(format.percentage(80.25, { rounding: Math.ceil })).toEqual("81%"); + expect(format.percentage(80.75, { rounding: Math.floor })).toEqual("80%"); + }); }); + + describe("accuracy", () => { + it("should floor decimals by default", () => { + //no decimals + const noDecimals = getInstance({ alwaysShowDecimalPlaces: false }); + expect(noDecimals.accuracy(12.75)).toEqual("12%"); + //with decimals + const withDecimals = getInstance({ alwaysShowDecimalPlaces: true }); + expect(withDecimals.accuracy(12.75)).toEqual("12.75%"); + }); + + it("should format with rounding", () => { + const format = getInstance({ alwaysShowDecimalPlaces: false }); + expect(format.accuracy(80.5)).toEqual("80%"); + expect(format.accuracy(80.25, { rounding: Math.ceil })).toEqual("81%"); + expect(format.accuracy(80.75, { rounding: Math.floor })).toEqual("80%"); + }); + }); + describe("decimals", () => { it("should format with decimalPlaces from configuration", () => { //no decimals @@ -188,6 +222,13 @@ describe("format.ts", () => { expect(format.decimals(null, { suffix: " raw" })).toEqual("-"); expect(format.decimals(undefined, { suffix: " raw" })).toEqual("-"); }); + + it("should format with rounding", () => { + const format = getInstance({ alwaysShowDecimalPlaces: false }); + expect(format.decimals(80.25)).toEqual("80"); + expect(format.decimals(80.25, { rounding: Math.ceil })).toEqual("81"); + expect(format.decimals(80.75, { rounding: Math.floor })).toEqual("80"); + }); }); }); diff --git a/frontend/src/ts/account/pb-tables.ts b/frontend/src/ts/account/pb-tables.ts index 4f1bcf0d67fd..6bc228d88c97 100644 --- a/frontend/src/ts/account/pb-tables.ts +++ b/frontend/src/ts/account/pb-tables.ts @@ -154,7 +154,7 @@ function buildPbHtml(
${Format.typingSpeed(pbData.wpm, { showDecimalPlaces: false, })}
-
${Format.percentage(pbData.acc, { +
${Format.accuracy(pbData.acc, { showDecimalPlaces: false, })}
@@ -164,10 +164,8 @@ function buildPbHtml( suffix: ` ${speedUnit}`, })}
${Format.typingSpeed(pbData.raw, { suffix: " raw" })}
-
${Format.percentage(pbData.acc, { suffix: " acc" })}
-
${Format.percentage(pbData.consistency, { - suffix: " con", - })}
+
${Format.accuracy(pbData.acc, { suffix: " acc" })}
+
${Format.percentage(pbData.consistency, { suffix: " con" })}
${dateText}
`; } catch (e) { diff --git a/frontend/src/ts/elements/modes-notice.ts b/frontend/src/ts/elements/modes-notice.ts index 79fd502d36ce..31d45460b7cf 100644 --- a/frontend/src/ts/elements/modes-notice.ts +++ b/frontend/src/ts/elements/modes-notice.ts @@ -144,13 +144,8 @@ export async function update(): Promise { } if (Config.showAverage !== "off") { - let avgWPM = Last10Average.getWPM(); - let avgAcc = Last10Average.getAcc(); - - if (!Config.alwaysShowDecimalPlaces) { - avgWPM = Math.round(avgWPM); - avgAcc = Math.round(avgAcc); - } + const avgWPM = Last10Average.getWPM(); + const avgAcc = Last10Average.getAcc(); if (isAuthenticated() && avgWPM > 0) { const avgWPMText = ["speed", "both"].includes(Config.showAverage) @@ -158,7 +153,7 @@ export async function update(): Promise { : ""; const avgAccText = ["acc", "both"].includes(Config.showAverage) - ? Format.percentage(avgAcc, { suffix: " acc" }) + ? Format.accuracy(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 f524bfb2e9c7..c6eba49defe5 100644 --- a/frontend/src/ts/pages/account.ts +++ b/frontend/src/ts/pages/account.ts @@ -881,9 +881,9 @@ async function fillContent(): Promise { $(".pageAccount .highestWpm .mode").html(topMode); $(".pageAccount .testsTaken .val").text(testCount); - $(".pageAccount .highestAcc .val").text(Format.percentage(topAcc)); - $(".pageAccount .avgAcc .val").text(Format.percentage(totalAcc / testCount)); - $(".pageAccount .avgAcc10 .val").text(Format.percentage(totalAcc10 / last10)); + $(".pageAccount .highestAcc .val").text(Format.accuracy(topAcc)); + $(".pageAccount .avgAcc .val").text(Format.accuracy(totalAcc / testCount)); + $(".pageAccount .avgAcc10 .val").text(Format.accuracy(totalAcc10 / last10)); if (totalCons === 0 || totalCons === undefined) { $(".pageAccount .avgCons .val").text("-"); diff --git a/frontend/src/ts/popups/pb-tables-popup.ts b/frontend/src/ts/popups/pb-tables-popup.ts index 86697a5c549e..5409fd5ece0c 100644 --- a/frontend/src/ts/popups/pb-tables-popup.ts +++ b/frontend/src/ts/popups/pb-tables-popup.ts @@ -63,7 +63,7 @@ function update(mode: SharedTypes.Config.Mode): void { ${Format.typingSpeed(pb.wpm)}
- ${Format.percentage(pb.acc)} + ${Format.accuracy(pb.acc)} ${Format.typingSpeed(pb.raw)} diff --git a/frontend/src/ts/test/result.ts b/frontend/src/ts/test/result.ts index 47631c3cf2f8..0259a803fe08 100644 --- a/frontend/src/ts/test/result.ts +++ b/frontend/src/ts/test/result.ts @@ -229,7 +229,7 @@ function updateWpmAndAcc(): void { } $("#result .stats .raw .bottom").text(Format.typingSpeed(result.rawWpm)); $("#result .stats .acc .bottom").text( - result.acc === 100 ? "100%" : Format.percentage(result.acc) + result.acc === 100 ? "100%" : Format.accuracy(result.acc) ); if (Config.alwaysShowDecimalPlaces) { diff --git a/frontend/src/ts/utils/format.ts b/frontend/src/ts/utils/format.ts index b9c63ae4a616..0fc217d29e7d 100644 --- a/frontend/src/ts/utils/format.ts +++ b/frontend/src/ts/utils/format.ts @@ -6,12 +6,14 @@ export type FormatOptions = { showDecimalPlaces?: boolean; suffix?: string; fallback?: string; + rounding?: (val: number) => number; }; const FORMAT_DEFAULT_OPTIONS: FormatOptions = { suffix: "", fallback: "-", showDecimalPlaces: undefined, + rounding: Math.round, }; export class Formatting { @@ -19,7 +21,7 @@ export class Formatting { typingSpeed( wpm: number | null | undefined, - formatOptions: FormatOptions = FORMAT_DEFAULT_OPTIONS + formatOptions: FormatOptions = {} ): string { const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions }; if (wpm === undefined || wpm === null) return options.fallback ?? ""; @@ -28,6 +30,7 @@ export class Formatting { return this.number(result, options); } + percentage( percentage: number | null | undefined, formatOptions: FormatOptions = {} @@ -38,6 +41,16 @@ export class Formatting { return this.number(percentage, options); } + accuracy( + accuracy: number | null | undefined, + formatOptions: FormatOptions = {} + ): string { + return this.percentage(accuracy, { + rounding: Math.floor, + ...formatOptions, + }); + } + decimals( value: number | null | undefined, formatOptions: FormatOptions = {} @@ -45,6 +58,7 @@ export class Formatting { const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions }; return this.number(value, options); } + private number( value: number | null | undefined, formatOptions: FormatOptions @@ -60,7 +74,7 @@ export class Formatting { ) { return Misc.roundTo2(value).toFixed(2) + suffix; } - return Math.round(value).toString() + suffix; + return (formatOptions.rounding ?? Math.round)(value).toString() + suffix; } }