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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions frontend/__tests__/components/modals/WordFilterModal.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { describe, expect, it } from "vitest";
import { filterWordList } from "../../../src/ts/components/modals/WordFilterModal";

const exactMatchFilter = {
include: "a r s t d h n e i o '",
exclude: "",
minLength: "",
maxLength: "",
regex: "",
exactMatch: true,
};

describe("filterWordList", () => {
it("filters against the British spelling", () => {
expect(filterWordList(exactMatchFilter, ["tire"], true)).toEqual({
words: [],
});
});

it("keeps the American spelling when British English is disabled", () => {
expect(filterWordList(exactMatchFilter, ["tire"])).toEqual({
words: ["tire"],
});
});

it("keeps the original word when its British spelling matches", () => {
expect(
filterWordList(
{ ...exactMatchFilter, include: "m a t h s" },
["math"],
true,
),
).toEqual({ words: ["math"] });
});

it("applies length filters to the British spelling", () => {
expect(
filterWordList(
{
...exactMatchFilter,
include: "m a t h s",
maxLength: "4",
},
["math"],
true,
),
).toEqual({ words: [] });
});
});
72 changes: 33 additions & 39 deletions frontend/__tests__/test/british-english.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,67 +6,61 @@ describe("british-english", () => {
describe("replace", () => {
beforeEach(() => (Config.mode = "time"));

it("should not replace words with no rule", async () => {
await expect(replace("test", "")).resolves.toEqual("test");
await expect(replace("Test", "")).resolves.toEqual("Test");
it("should not replace words with no rule", () => {
expect(replace("test", "")).toEqual("test");
expect(replace("Test", "")).toEqual("Test");
});

it("should replace words", async () => {
await expect(replace("math", "")).resolves.toEqual("maths");
await expect(replace("Math", "")).resolves.toEqual("Maths");
it("should replace words", () => {
expect(replace("math", "")).toEqual("maths");
expect(replace("Math", "")).toEqual("Maths");
});

it("should replace words with non-word characters around", async () => {
await expect(replace(" :math-. ", "")).resolves.toEqual(" :maths-. ");
await expect(replace(" :Math-. ", "")).resolves.toEqual(" :Maths-. ");
it("should replace words with non-word characters around", () => {
expect(replace(" :math-. ", "")).toEqual(" :maths-. ");
expect(replace(" :Math-. ", "")).toEqual(" :Maths-. ");
});

it("should not replace in quote mode if previousWord matches excepted words", async () => {
it("should not replace in quote mode if previousWord matches excepted words", () => {
//GIVEN
Config.mode = "quote";

//WHEN/THEN
await expect(replace("tire", "will")).resolves.toEqual("tire");
await expect(replace("tire", "")).resolves.toEqual("tyre");
expect(replace("tire", "will")).toEqual("tire");
expect(replace("tire", "")).toEqual("tyre");
});

it("should replace hyphenated words", async () => {
await expect(replace("cream-colored", "")).resolves.toEqual(
"cream-coloured",
);
await expect(replace("armor-flavoring", "")).resolves.toEqual(
"armour-flavouring",
);
it("should replace hyphenated words", () => {
expect(replace("cream-colored", "")).toEqual("cream-coloured");
expect(replace("armor-flavoring", "")).toEqual("armour-flavouring");
});

it("should convert double quotes to single quotes", async () => {
await expect(replace('"hello"', "")).resolves.toEqual("'hello'");
await expect(replace('"test"', "")).resolves.toEqual("'test'");
await expect(replace('"Hello World"', "")).resolves.toEqual(
"'Hello World'",
);
it("should convert double quotes to single quotes", () => {
expect(replace('"hello"', "")).toEqual("'hello'");
expect(replace('"test"', "")).toEqual("'test'");
expect(replace('"Hello World"', "")).toEqual("'Hello World'");
});

it("should convert double quotes and replace words", async () => {
await expect(replace('"color"', "")).resolves.toEqual("'colour'");
await expect(replace('"math"', "")).resolves.toEqual("'maths'");
await expect(replace('"Color"', "")).resolves.toEqual("'Colour'");
it("should convert double quotes and replace words", () => {
expect(replace('"color"', "")).toEqual("'colour'");
expect(replace('"math"', "")).toEqual("'maths'");
expect(replace('"Color"', "")).toEqual("'Colour'");
});

it("should handle multiple double quotes in a word", async () => {
await expect(
replace('He said "hello" and "goodbye"', ""),
).resolves.toEqual("He said 'hello' and 'goodbye'");
it("should handle multiple double quotes in a word", () => {
expect(replace('He said "hello" and "goodbye"', "")).toEqual(
"He said 'hello' and 'goodbye'",
);
});

it("should not affect words without double quotes", async () => {
await expect(replace("'hello'", "")).resolves.toEqual("'hello'");
await expect(replace("test", "")).resolves.toEqual("test");
it("should not affect words without double quotes", () => {
expect(replace("'hello'", "")).toEqual("'hello'");
expect(replace("test", "")).toEqual("test");
});

it("ignores prototype-related property names (e.g. constructor, __proto__)", async () => {
await expect(replace("constructor", "")).resolves.toEqual("constructor");
await expect(replace("__proto__", "")).resolves.toEqual("__proto__");
it("ignores prototype-related property names (e.g. constructor, __proto__)", () => {
expect(replace("constructor", "")).toEqual("constructor");
expect(replace("__proto__", "")).toEqual("__proto__");
});
});
});
29 changes: 21 additions & 8 deletions frontend/src/ts/components/modals/WordFilterModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Setter,
} from "solid-js";

import { Config } from "../../config/store";
import { LanguageList } from "../../constants/languages";
import { LayoutsList } from "../../constants/layouts";
import { createDebouncedSignal } from "../../hooks/createDebouncedSignal";
Expand All @@ -20,6 +21,7 @@ import {
showNoticeNotification,
showErrorNotification,
} from "../../states/notifications";
import * as BritishEnglish from "../../test/british-english";
import * as JSONData from "../../utils/json-data";
import * as Misc from "../../utils/misc";
import { AnimatedModal } from "../common/AnimatedModal";
Expand Down Expand Up @@ -122,9 +124,10 @@ type FilterFormValues = {

type FilterResult = { words: string[] } | { error: string };

function filterWordList(
export function filterWordList(
value: FilterFormValues,
words: string[],
useBritishEnglish = false,
): FilterResult {
const exactMatchOnly = value.exactMatch;

Expand Down Expand Up @@ -162,16 +165,19 @@ function filterWordList(

const filteredWords: string[] = [];
for (const word of words) {
const testincl = regincl.test(word);
const wordToTest = useBritishEnglish
? BritishEnglish.replace(word, undefined)
: word;
const testincl = regincl.test(wordToTest);
const testexcl =
exactMatchOnly || filterout === "" ? false : regexcl.test(word);
const testlit = exactMatchOnly ? true : reglit.test(word);
exactMatchOnly || filterout === "" ? false : regexcl.test(wordToTest);
const testlit = exactMatchOnly ? true : reglit.test(wordToTest);
if (
testincl &&
!testexcl &&
testlit &&
word.length <= max &&
word.length >= min
wordToTest.length <= max &&
wordToTest.length >= min
) {
filteredWords.push(word);
}
Expand All @@ -189,6 +195,9 @@ export function WordFilterModal(props: {

let submitAction: "set" | "add" = "set";

const useBritishEnglish = () =>
Config.britishEnglish && Config.language.includes("english");

const form = createForm(() => ({
defaultValues: {
include: "",
Expand All @@ -211,7 +220,11 @@ export function WordFilterModal(props: {
return;
}

const result = filterWordList(value, languageWordList.words);
const result = filterWordList(
value,
languageWordList.words,
useBritishEnglish(),
);
if ("error" in result) {
showNoticeNotification(result.error);
return;
Expand Down Expand Up @@ -248,7 +261,7 @@ export function WordFilterModal(props: {
const matchResult = createMemo<FilterResult | null>(() => {
const words = languageWords();
if (words === null || words === undefined) return null;
return filterWordList(debouncedValues(), words);
return filterWordList(debouncedValues(), words, useBritishEnglish());
});

const applyPreset = async () => {
Expand Down
13 changes: 6 additions & 7 deletions frontend/src/ts/test/british-english.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { Config } from "../config/store";
import britishEnglishReplacements from "../constants/british-english";
import { capitalizeFirstLetterOfEachWord } from "../utils/strings";

export async function replace(
export function replace(
word: string,
previousWord: string | undefined,
): Promise<string> {
): string {
// Convert American-style double quotes to British-style single quotes
if (word.includes('"')) {
word = word.replace(/"/g, "'");
Expand All @@ -14,11 +14,10 @@ export async function replace(
if (word.includes("-")) {
//this handles hyphenated words (for example "cream-colored") to make sure
//we don't have to add every possible combination to the list
return (
await Promise.all(
word.split("-").map(async (w) => replace(w, previousWord)),
)
).join("-");
return word
.split("-")
.map((wordPart) => replace(wordPart, previousWord))
.join("-");
} else {
const cleanedWord = word.replace(/^[\W]+|[\W]+$/g, "").toLowerCase();
if (
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/ts/test/words-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,10 +372,10 @@ function applyFunboxesToWord(
return word;
}

async function applyBritishEnglishToWord(
function applyBritishEnglishToWord(
word: string,
previousWord: string | undefined,
): Promise<string> {
): string {
if (!Config.britishEnglish) return word;
if (!Config.language.includes("english")) return word;
const currentQuote = getCurrentQuote();
Expand All @@ -387,7 +387,7 @@ async function applyBritishEnglishToWord(
return word;
}

return await BritishEnglish.replace(word, previousWord);
return BritishEnglish.replace(word, previousWord);
}

function applyLazyModeToWord(word: string, language: LanguageObject): string {
Expand Down Expand Up @@ -952,7 +952,7 @@ export async function getNextWord(
);
}

randomWord = await applyBritishEnglishToWord(randomWord, previousWordRaw);
randomWord = applyBritishEnglishToWord(randomWord, previousWordRaw);

if (Config.numbers) {
if (random() < 0.1) {
Expand Down
Loading