mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-09-05 22:28:01 +08:00
refactor(config): split config and config-metadata tests (@fehmer) (#6770)
This commit is contained in:
parent
e357efc435
commit
4f57418b6a
4 changed files with 486 additions and 429 deletions
278
frontend/__tests__/root/config-metadata.spec.ts
Normal file
278
frontend/__tests__/root/config-metadata.spec.ts
Normal file
|
@ -0,0 +1,278 @@
|
|||
import { configMetadata } from "../../src/ts/config-metadata";
|
||||
import * as Config from "../../src/ts/config";
|
||||
import { ConfigKey, Config as ConfigType } from "@monkeytype/schemas/configs";
|
||||
|
||||
const { replaceConfig, getConfig } = Config.__testing;
|
||||
|
||||
type TestsByConfig<T> = Partial<{
|
||||
[K in keyof ConfigType]: (T & { value: ConfigType[K] })[];
|
||||
}>;
|
||||
|
||||
describe("ConfigMeta", () => {
|
||||
afterAll(() => {
|
||||
replaceConfig({});
|
||||
vi.resetModules();
|
||||
});
|
||||
it("should have changeRequiresRestart defined", () => {
|
||||
const configsRequiringRestarts = Object.entries(configMetadata)
|
||||
.filter(([_key, value]) => value.changeRequiresRestart === true)
|
||||
.map(([key]) => key)
|
||||
.sort();
|
||||
|
||||
expect(configsRequiringRestarts).toEqual(
|
||||
[
|
||||
"punctuation",
|
||||
"numbers",
|
||||
"words",
|
||||
"time",
|
||||
"mode",
|
||||
"quoteLength",
|
||||
"language",
|
||||
"difficulty",
|
||||
"minWpmCustomSpeed",
|
||||
"minWpm",
|
||||
"minAcc",
|
||||
"minAccCustom",
|
||||
"minBurst",
|
||||
"minBurstCustomSpeed",
|
||||
"britishEnglish",
|
||||
"funbox",
|
||||
"customLayoutfluid",
|
||||
"strictSpace",
|
||||
"stopOnError",
|
||||
"lazyMode",
|
||||
"layout",
|
||||
"codeUnindentOnBackspace",
|
||||
].sort()
|
||||
);
|
||||
});
|
||||
|
||||
it("should have triggerResize defined", () => {
|
||||
const configsWithTriggeResize = Object.entries(configMetadata)
|
||||
.filter(([_key, value]) => value.triggerResize === true)
|
||||
.map(([key]) => key)
|
||||
.sort();
|
||||
|
||||
expect(configsWithTriggeResize).toEqual(
|
||||
["fontSize", "keymapSize", "maxLineWidth", "tapeMode"].sort()
|
||||
);
|
||||
});
|
||||
describe("overrideValue", () => {
|
||||
const testCases: TestsByConfig<{
|
||||
given?: Partial<ConfigType>;
|
||||
expected: Partial<ConfigType>;
|
||||
}> = {
|
||||
punctuation: [
|
||||
{ value: true, expected: { punctuation: true } },
|
||||
{
|
||||
value: true,
|
||||
given: { mode: "quote" },
|
||||
expected: { punctuation: false },
|
||||
},
|
||||
],
|
||||
numbers: [
|
||||
{ value: true, expected: { numbers: true } },
|
||||
{
|
||||
value: true,
|
||||
given: { mode: "quote" },
|
||||
expected: { numbers: false },
|
||||
},
|
||||
],
|
||||
customLayoutfluid: [
|
||||
{
|
||||
value: ["qwerty", "qwerty", "qwertz"],
|
||||
expected: { customLayoutfluid: ["qwerty", "qwertz"] },
|
||||
},
|
||||
],
|
||||
customPolyglot: [
|
||||
{
|
||||
value: ["english", "polish", "english"],
|
||||
expected: { customPolyglot: ["english", "polish"] },
|
||||
},
|
||||
],
|
||||
keymapSize: [
|
||||
{ value: 1, expected: { keymapSize: 1 } },
|
||||
{ value: 1.234, expected: { keymapSize: 1.2 } },
|
||||
{ value: 0.4, expected: { keymapSize: 0.5 } },
|
||||
{ value: 3.6, expected: { keymapSize: 3.5 } },
|
||||
],
|
||||
customBackground: [
|
||||
{
|
||||
value: " https://example.com/test.jpg ",
|
||||
expected: { customBackground: "https://example.com/test.jpg" },
|
||||
},
|
||||
],
|
||||
accountChart: [
|
||||
{
|
||||
value: ["on", "off", "off", "off"],
|
||||
expected: { accountChart: ["on", "off", "off", "off"] },
|
||||
},
|
||||
{
|
||||
value: ["off", "off", "off", "off"],
|
||||
given: { accountChart: ["on", "off", "off", "off"] },
|
||||
expected: { accountChart: ["off", "on", "off", "off"] },
|
||||
},
|
||||
{
|
||||
value: ["off", "off", "on", "on"],
|
||||
given: { accountChart: ["off", "on", "off", "off"] },
|
||||
expected: { accountChart: ["on", "off", "on", "on"] },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it.for(
|
||||
Object.entries(testCases).flatMap(([key, value]) =>
|
||||
value.flatMap((it) => ({ key: key as ConfigKey, ...it }))
|
||||
)
|
||||
)(
|
||||
`$key value=$value given=$given expect=$expected`,
|
||||
({ key, value, given, expected }) => {
|
||||
//GIVEN
|
||||
replaceConfig(given ?? {});
|
||||
|
||||
//WHEN
|
||||
Config.genericSet(key, value as any);
|
||||
|
||||
//THEN
|
||||
expect(getConfig()).toMatchObject(expected);
|
||||
}
|
||||
);
|
||||
});
|
||||
describe("isBlocked", () => {
|
||||
const testCases: TestsByConfig<{
|
||||
given?: Partial<ConfigType>;
|
||||
fail?: true;
|
||||
}> = {
|
||||
funbox: [
|
||||
{
|
||||
value: "gibberish" as any,
|
||||
given: { mode: "quote" },
|
||||
fail: true,
|
||||
},
|
||||
],
|
||||
showAllLines: [
|
||||
{ value: true, given: { tapeMode: "off" } },
|
||||
{ value: false, given: { tapeMode: "word" } },
|
||||
{ value: true, given: { tapeMode: "word" }, fail: true },
|
||||
],
|
||||
};
|
||||
|
||||
it.for(
|
||||
Object.entries(testCases).flatMap(([key, value]) =>
|
||||
value.flatMap((it) => ({ key: key as ConfigKey, ...it }))
|
||||
)
|
||||
)(
|
||||
`$key value=$value given=$given fail=$fail`,
|
||||
({ key, value, given, fail }) => {
|
||||
//GIVEN
|
||||
replaceConfig(given ?? {});
|
||||
|
||||
//WHEN
|
||||
const applied = Config.genericSet(key, value as any);
|
||||
|
||||
//THEN
|
||||
expect(applied).toEqual(!fail);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe("overrideConfig", () => {
|
||||
const testCases: TestsByConfig<{
|
||||
given: Partial<ConfigType>;
|
||||
expected?: Partial<ConfigType>;
|
||||
}> = {
|
||||
mode: [
|
||||
{ value: "time", given: { numbers: true, punctuation: true } },
|
||||
{
|
||||
value: "custom",
|
||||
given: { numbers: true, punctuation: true },
|
||||
expected: { numbers: false, punctuation: false },
|
||||
},
|
||||
{
|
||||
value: "quote",
|
||||
given: { numbers: true, punctuation: true },
|
||||
expected: { numbers: false, punctuation: false },
|
||||
},
|
||||
{
|
||||
value: "zen",
|
||||
given: { numbers: true, punctuation: true },
|
||||
expected: { numbers: false, punctuation: false },
|
||||
},
|
||||
],
|
||||
numbers: [{ value: false, given: { mode: "quote" } }],
|
||||
freedomMode: [
|
||||
{
|
||||
value: false,
|
||||
given: { confidenceMode: "on" },
|
||||
expected: { confidenceMode: "on" },
|
||||
},
|
||||
{
|
||||
value: true,
|
||||
given: { confidenceMode: "on" },
|
||||
expected: { confidenceMode: "off" },
|
||||
},
|
||||
],
|
||||
stopOnError: [
|
||||
{
|
||||
value: "off",
|
||||
given: { confidenceMode: "on" },
|
||||
expected: { confidenceMode: "on" },
|
||||
},
|
||||
{
|
||||
value: "word",
|
||||
given: { confidenceMode: "on" },
|
||||
expected: { confidenceMode: "off" },
|
||||
},
|
||||
],
|
||||
confidenceMode: [
|
||||
{
|
||||
value: "off",
|
||||
given: { freedomMode: true, stopOnError: "word" },
|
||||
expected: { freedomMode: true, stopOnError: "word" },
|
||||
},
|
||||
{
|
||||
value: "on",
|
||||
given: { freedomMode: true, stopOnError: "word" },
|
||||
expected: { freedomMode: false, stopOnError: "off" },
|
||||
},
|
||||
],
|
||||
tapeMode: [
|
||||
{
|
||||
value: "off",
|
||||
given: { showAllLines: true },
|
||||
expected: { showAllLines: true },
|
||||
},
|
||||
{
|
||||
value: "letter",
|
||||
given: { showAllLines: true },
|
||||
expected: { showAllLines: false },
|
||||
},
|
||||
],
|
||||
theme: [
|
||||
{
|
||||
value: "8008",
|
||||
given: { customTheme: true },
|
||||
expected: { customTheme: false },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it.for(
|
||||
Object.entries(testCases).flatMap(([key, value]) =>
|
||||
value.flatMap((it) => ({ key: key as ConfigKey, ...it }))
|
||||
)
|
||||
)(
|
||||
`$key value=$value given=$given expected=$expected`,
|
||||
({ key, value, given, expected }) => {
|
||||
//GIVEN
|
||||
replaceConfig(given);
|
||||
|
||||
//WHEN
|
||||
Config.genericSet(key, value as any);
|
||||
|
||||
//THEN
|
||||
expect(getConfig()).toMatchObject(expected ?? {});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
|
@ -4,7 +4,7 @@ import {
|
|||
CustomThemeColors,
|
||||
FunboxName,
|
||||
ConfigKey,
|
||||
Config as ConfigType,
|
||||
CaretStyleSchema,
|
||||
} from "@monkeytype/schemas/configs";
|
||||
import { randomBytes } from "crypto";
|
||||
import { vi } from "vitest";
|
||||
|
@ -15,66 +15,60 @@ import * as DB from "../../src/ts/db";
|
|||
import * as AccountButton from "../../src/ts/elements/account-button";
|
||||
import * as Notifications from "../../src/ts/elements/notifications";
|
||||
|
||||
type TestsByConfig<T> = Partial<{
|
||||
[K in keyof ConfigType]: (T & { value: ConfigType[K] })[];
|
||||
}>;
|
||||
|
||||
const { configMetadata, replaceConfig, getConfig } = Config.__testing;
|
||||
const { replaceConfig, getConfig } = Config.__testing;
|
||||
|
||||
describe("Config", () => {
|
||||
const isDevEnvironmentMock = vi.spyOn(Misc, "isDevEnvironment");
|
||||
beforeEach(() => isDevEnvironmentMock.mockReset());
|
||||
describe("test with mocks", () => {
|
||||
const isDevEnvironmentMock = vi.spyOn(Misc, "isDevEnvironment");
|
||||
|
||||
const canSetConfigWithCurrentFunboxesMock = vi.spyOn(
|
||||
FunboxValidation,
|
||||
"canSetConfigWithCurrentFunboxes"
|
||||
);
|
||||
const isConfigValueValidMock = vi.spyOn(
|
||||
ConfigValidation,
|
||||
"isConfigValueValid"
|
||||
);
|
||||
const dispatchConfigEventMock = vi.spyOn(ConfigEvent, "dispatch");
|
||||
const dbSaveConfigMock = vi.spyOn(DB, "saveConfig");
|
||||
const accountButtonLoadingMock = vi.spyOn(AccountButton, "loading");
|
||||
const notificationAddMock = vi.spyOn(Notifications, "add");
|
||||
const miscReloadAfterMock = vi.spyOn(Misc, "reloadAfter");
|
||||
const miscTriggerResizeMock = vi.spyOn(Misc, "triggerResize");
|
||||
|
||||
const mocks = [
|
||||
canSetConfigWithCurrentFunboxesMock,
|
||||
isConfigValueValidMock,
|
||||
dispatchConfigEventMock,
|
||||
dbSaveConfigMock,
|
||||
accountButtonLoadingMock,
|
||||
notificationAddMock,
|
||||
miscReloadAfterMock,
|
||||
miscTriggerResizeMock,
|
||||
];
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.useFakeTimers();
|
||||
mocks.forEach((it) => it.mockReset());
|
||||
|
||||
vi.mock("../../src/ts/test/test-state", () => ({
|
||||
isActive: true,
|
||||
}));
|
||||
|
||||
isConfigValueValidMock.mockReturnValue(true);
|
||||
canSetConfigWithCurrentFunboxesMock.mockReturnValue(true);
|
||||
dbSaveConfigMock.mockResolvedValue();
|
||||
|
||||
describe("configMeta", () => {
|
||||
afterAll(() => {
|
||||
replaceConfig({});
|
||||
vi.resetModules();
|
||||
});
|
||||
it("should have changeRequiresRestart defined", () => {
|
||||
const configsRequiringRestarts = Object.entries(configMetadata)
|
||||
.filter(([_key, value]) => value.changeRequiresRestart === true)
|
||||
.map(([key]) => key)
|
||||
.sort();
|
||||
|
||||
expect(configsRequiringRestarts).toEqual(
|
||||
[
|
||||
"punctuation",
|
||||
"numbers",
|
||||
"words",
|
||||
"time",
|
||||
"mode",
|
||||
"quoteLength",
|
||||
"language",
|
||||
"difficulty",
|
||||
"minWpmCustomSpeed",
|
||||
"minWpm",
|
||||
"minAcc",
|
||||
"minAccCustom",
|
||||
"minBurst",
|
||||
"minBurstCustomSpeed",
|
||||
"britishEnglish",
|
||||
"funbox",
|
||||
"customLayoutfluid",
|
||||
"strictSpace",
|
||||
"stopOnError",
|
||||
"lazyMode",
|
||||
"layout",
|
||||
"codeUnindentOnBackspace",
|
||||
].sort()
|
||||
);
|
||||
});
|
||||
|
||||
it("should have triggerResize defined", () => {
|
||||
const configsWithTriggeResize = Object.entries(configMetadata)
|
||||
.filter(([_key, value]) => value.triggerResize === true)
|
||||
.map(([key]) => key)
|
||||
.sort();
|
||||
|
||||
expect(configsWithTriggeResize).toEqual(
|
||||
["fontSize", "keymapSize", "maxLineWidth", "tapeMode"].sort()
|
||||
);
|
||||
afterAll(() => {
|
||||
mocks.forEach((it) => it.mockRestore());
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
beforeEach(() => isDevEnvironmentMock.mockReset());
|
||||
|
||||
it("should throw if config key in not found in metadata", () => {
|
||||
expect(() => {
|
||||
Config.genericSet("nonExistentKey" as ConfigKey, true);
|
||||
|
@ -83,417 +77,198 @@ describe("Config", () => {
|
|||
);
|
||||
});
|
||||
|
||||
describe("overrideValue", () => {
|
||||
const testCases: TestsByConfig<{
|
||||
given?: Partial<ConfigType>;
|
||||
expected: Partial<ConfigType>;
|
||||
}> = {
|
||||
punctuation: [
|
||||
{ value: true, expected: { punctuation: true } },
|
||||
{
|
||||
value: true,
|
||||
given: { mode: "quote" },
|
||||
expected: { punctuation: false },
|
||||
},
|
||||
],
|
||||
numbers: [
|
||||
{ value: true, expected: { numbers: true } },
|
||||
{
|
||||
value: true,
|
||||
given: { mode: "quote" },
|
||||
expected: { numbers: false },
|
||||
},
|
||||
],
|
||||
customLayoutfluid: [
|
||||
{
|
||||
value: ["qwerty", "qwerty", "qwertz"],
|
||||
expected: { customLayoutfluid: ["qwerty", "qwertz"] },
|
||||
},
|
||||
],
|
||||
customPolyglot: [
|
||||
{
|
||||
value: ["english", "polish", "english"],
|
||||
expected: { customPolyglot: ["english", "polish"] },
|
||||
},
|
||||
],
|
||||
keymapSize: [
|
||||
{ value: 1, expected: { keymapSize: 1 } },
|
||||
{ value: 1.234, expected: { keymapSize: 1.2 } },
|
||||
{ value: 0.4, expected: { keymapSize: 0.5 } },
|
||||
{ value: 3.6, expected: { keymapSize: 3.5 } },
|
||||
],
|
||||
customBackground: [
|
||||
{
|
||||
value: " https://example.com/test.jpg ",
|
||||
expected: { customBackground: "https://example.com/test.jpg" },
|
||||
},
|
||||
],
|
||||
accountChart: [
|
||||
{
|
||||
value: ["on", "off", "off", "off"],
|
||||
expected: { accountChart: ["on", "off", "off", "off"] },
|
||||
},
|
||||
{
|
||||
value: ["off", "off", "off", "off"],
|
||||
given: { accountChart: ["on", "off", "off", "off"] },
|
||||
expected: { accountChart: ["off", "on", "off", "off"] },
|
||||
},
|
||||
{
|
||||
value: ["off", "off", "on", "on"],
|
||||
given: { accountChart: ["off", "on", "off", "off"] },
|
||||
expected: { accountChart: ["on", "off", "on", "on"] },
|
||||
},
|
||||
],
|
||||
};
|
||||
it("fails if test is active and funbox no_quit", () => {
|
||||
//GIVEN
|
||||
replaceConfig({ funbox: ["no_quit"], numbers: false });
|
||||
|
||||
it.for(
|
||||
Object.entries(testCases).flatMap(([key, value]) =>
|
||||
value.flatMap((it) => ({ key: key as ConfigKey, ...it }))
|
||||
)
|
||||
)(
|
||||
`$key value=$value given=$given expect=$expected`,
|
||||
({ key, value, given, expected }) => {
|
||||
//GIVEN
|
||||
replaceConfig(given ?? {});
|
||||
//WHEN
|
||||
expect(Config.genericSet("numbers", true, true)).toBe(false);
|
||||
|
||||
//WHEN
|
||||
Config.genericSet(key, value as any);
|
||||
|
||||
//THEN
|
||||
expect(getConfig()).toMatchObject(expected);
|
||||
//THEN
|
||||
expect(notificationAddMock).toHaveBeenCalledWith(
|
||||
"No quit funbox is active. Please finish the test.",
|
||||
0,
|
||||
{
|
||||
important: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe("isBlocked", () => {
|
||||
const testCases: TestsByConfig<{
|
||||
given?: Partial<ConfigType>;
|
||||
fail?: true;
|
||||
}> = {
|
||||
funbox: [
|
||||
{
|
||||
value: "gibberish" as any,
|
||||
given: { mode: "quote" },
|
||||
fail: true,
|
||||
},
|
||||
],
|
||||
showAllLines: [
|
||||
{ value: true, given: { tapeMode: "off" } },
|
||||
{ value: false, given: { tapeMode: "word" } },
|
||||
{ value: true, given: { tapeMode: "word" }, fail: true },
|
||||
],
|
||||
};
|
||||
//TODO isBlocked
|
||||
it("should fail if config is blocked", () => {
|
||||
//GIVEN
|
||||
replaceConfig({ tapeMode: "letter" });
|
||||
|
||||
it.for(
|
||||
Object.entries(testCases).flatMap(([key, value]) =>
|
||||
value.flatMap((it) => ({ key: key as ConfigKey, ...it }))
|
||||
)
|
||||
)(
|
||||
`$key value=$value given=$given fail=$fail`,
|
||||
({ key, value, given, fail }) => {
|
||||
//GIVEN
|
||||
replaceConfig(given ?? {});
|
||||
//WHEN / THEN
|
||||
expect(Config.genericSet("showAllLines", true)).toBe(false);
|
||||
});
|
||||
|
||||
//WHEN
|
||||
const applied = Config.genericSet(key, value as any);
|
||||
it("should use overrideValue", () => {
|
||||
//WHEN
|
||||
Config.genericSet("customLayoutfluid", ["3l", "ABNT2", "3l"]);
|
||||
|
||||
//THEN
|
||||
expect(applied).toEqual(!fail);
|
||||
}
|
||||
//THEN
|
||||
expect(getConfig().customLayoutfluid).toEqual(["3l", "ABNT2"]);
|
||||
});
|
||||
|
||||
it("fails if config is invalid", () => {
|
||||
//GIVEN
|
||||
isConfigValueValidMock.mockReturnValue(false);
|
||||
|
||||
//WHEN / THEN
|
||||
expect(Config.genericSet("caretStyle", "banana" as any)).toBe(false);
|
||||
expect(isConfigValueValidMock).toHaveBeenCalledWith(
|
||||
"caret style",
|
||||
"banana",
|
||||
CaretStyleSchema
|
||||
);
|
||||
});
|
||||
|
||||
describe("overrideConfig", () => {
|
||||
const testCases: TestsByConfig<{
|
||||
given: Partial<ConfigType>;
|
||||
expected?: Partial<ConfigType>;
|
||||
}> = {
|
||||
mode: [
|
||||
{ value: "time", given: { numbers: true, punctuation: true } },
|
||||
{
|
||||
value: "custom",
|
||||
given: { numbers: true, punctuation: true },
|
||||
expected: { numbers: false, punctuation: false },
|
||||
},
|
||||
{
|
||||
value: "quote",
|
||||
given: { numbers: true, punctuation: true },
|
||||
expected: { numbers: false, punctuation: false },
|
||||
},
|
||||
{
|
||||
value: "zen",
|
||||
given: { numbers: true, punctuation: true },
|
||||
expected: { numbers: false, punctuation: false },
|
||||
},
|
||||
],
|
||||
numbers: [{ value: false, given: { mode: "quote" } }],
|
||||
freedomMode: [
|
||||
{
|
||||
value: false,
|
||||
given: { confidenceMode: "on" },
|
||||
expected: { confidenceMode: "on" },
|
||||
},
|
||||
{
|
||||
value: true,
|
||||
given: { confidenceMode: "on" },
|
||||
expected: { confidenceMode: "off" },
|
||||
},
|
||||
],
|
||||
stopOnError: [
|
||||
{
|
||||
value: "off",
|
||||
given: { confidenceMode: "on" },
|
||||
expected: { confidenceMode: "on" },
|
||||
},
|
||||
{
|
||||
value: "word",
|
||||
given: { confidenceMode: "on" },
|
||||
expected: { confidenceMode: "off" },
|
||||
},
|
||||
],
|
||||
confidenceMode: [
|
||||
{
|
||||
value: "off",
|
||||
given: { freedomMode: true, stopOnError: "word" },
|
||||
expected: { freedomMode: true, stopOnError: "word" },
|
||||
},
|
||||
{
|
||||
value: "on",
|
||||
given: { freedomMode: true, stopOnError: "word" },
|
||||
expected: { freedomMode: false, stopOnError: "off" },
|
||||
},
|
||||
],
|
||||
tapeMode: [
|
||||
{
|
||||
value: "off",
|
||||
given: { showAllLines: true },
|
||||
expected: { showAllLines: true },
|
||||
},
|
||||
{
|
||||
value: "letter",
|
||||
given: { showAllLines: true },
|
||||
expected: { showAllLines: false },
|
||||
},
|
||||
],
|
||||
theme: [
|
||||
{
|
||||
value: "8008",
|
||||
given: { customTheme: true },
|
||||
expected: { customTheme: false },
|
||||
},
|
||||
],
|
||||
};
|
||||
it("cannot set if funbox disallows", () => {
|
||||
//GIVEN
|
||||
canSetConfigWithCurrentFunboxesMock.mockReturnValue(false);
|
||||
|
||||
it.for(
|
||||
Object.entries(testCases).flatMap(([key, value]) =>
|
||||
value.flatMap((it) => ({ key: key as ConfigKey, ...it }))
|
||||
)
|
||||
)(
|
||||
`$key value=$value given=$given expected=$expected`,
|
||||
({ key, value, given, expected }) => {
|
||||
//GIVEN
|
||||
replaceConfig(given);
|
||||
//WHEN / THEN
|
||||
expect(Config.genericSet("numbers", true)).toBe(false);
|
||||
});
|
||||
|
||||
//WHEN
|
||||
Config.genericSet(key, value as any);
|
||||
it("sets overrideConfigs", () => {
|
||||
//GIVEN
|
||||
replaceConfig({
|
||||
confidenceMode: "off",
|
||||
freedomMode: false, //already set correctly
|
||||
stopOnError: "letter", //should get updated
|
||||
});
|
||||
|
||||
//THEN
|
||||
expect(getConfig()).toMatchObject(expected ?? {});
|
||||
}
|
||||
//WHEN
|
||||
Config.genericSet("confidenceMode", "max");
|
||||
|
||||
//THEN
|
||||
expect(dispatchConfigEventMock).not.toHaveBeenCalledWith(
|
||||
"freedomMode",
|
||||
false,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
expect(dispatchConfigEventMock).toHaveBeenCalledWith(
|
||||
"stopOnError",
|
||||
"off",
|
||||
true,
|
||||
"letter"
|
||||
);
|
||||
|
||||
expect(dispatchConfigEventMock).toHaveBeenCalledWith(
|
||||
"confidenceMode",
|
||||
"max",
|
||||
false,
|
||||
"off"
|
||||
);
|
||||
});
|
||||
|
||||
describe("test with mocks", () => {
|
||||
const canSetConfigWithCurrentFunboxesMock = vi.spyOn(
|
||||
FunboxValidation,
|
||||
"canSetConfigWithCurrentFunboxes"
|
||||
it("saves to localstorage if nosave=false", async () => {
|
||||
//GIVEN
|
||||
replaceConfig({ numbers: false });
|
||||
|
||||
//WHEN
|
||||
Config.genericSet("numbers", true);
|
||||
|
||||
//THEN
|
||||
//wait for debounce
|
||||
await vi.advanceTimersByTimeAsync(2500);
|
||||
|
||||
//show loading
|
||||
expect(accountButtonLoadingMock).toHaveBeenNthCalledWith(1, true);
|
||||
|
||||
//save
|
||||
expect(dbSaveConfigMock).toHaveBeenCalledWith({ numbers: true });
|
||||
|
||||
//hide loading
|
||||
expect(accountButtonLoadingMock).toHaveBeenNthCalledWith(2, false);
|
||||
|
||||
//send event
|
||||
expect(dispatchConfigEventMock).toHaveBeenCalledWith(
|
||||
"saveToLocalStorage",
|
||||
expect.stringContaining("numbers")
|
||||
);
|
||||
const isConfigValueValidMock = vi.spyOn(
|
||||
ConfigValidation,
|
||||
"isConfigValueValid"
|
||||
});
|
||||
it("does not save to localstorage if nosave=true", async () => {
|
||||
//GIVEN
|
||||
|
||||
replaceConfig({ numbers: false });
|
||||
|
||||
//WHEN
|
||||
Config.genericSet("numbers", true, true);
|
||||
|
||||
//THEN
|
||||
//wait for debounce
|
||||
await vi.advanceTimersByTimeAsync(2500);
|
||||
|
||||
expect(accountButtonLoadingMock).not.toHaveBeenCalled();
|
||||
expect(dbSaveConfigMock).not.toHaveBeenCalled();
|
||||
|
||||
expect(dispatchConfigEventMock).not.toHaveBeenCalledWith(
|
||||
"saveToLocalStorage",
|
||||
expect.any(String)
|
||||
);
|
||||
const dispatchConfigEventMock = vi.spyOn(ConfigEvent, "dispatch");
|
||||
const dbSaveConfigMock = vi.spyOn(DB, "saveConfig");
|
||||
const accountButtonLoadingMock = vi.spyOn(AccountButton, "loading");
|
||||
const notificationAddMock = vi.spyOn(Notifications, "add");
|
||||
const miscReloadAfterMock = vi.spyOn(Misc, "reloadAfter");
|
||||
});
|
||||
|
||||
const mocks = [
|
||||
canSetConfigWithCurrentFunboxesMock,
|
||||
isConfigValueValidMock,
|
||||
dispatchConfigEventMock,
|
||||
dbSaveConfigMock,
|
||||
accountButtonLoadingMock,
|
||||
notificationAddMock,
|
||||
miscReloadAfterMock,
|
||||
];
|
||||
it("dispatches event on set", () => {
|
||||
//GIVEN
|
||||
replaceConfig({ numbers: false });
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.useFakeTimers();
|
||||
mocks.forEach((it) => it.mockReset());
|
||||
//WHEN
|
||||
Config.genericSet("numbers", true, true);
|
||||
|
||||
vi.mock("../../src/ts/test/test-state", () => ({
|
||||
isActive: true,
|
||||
}));
|
||||
//THEN
|
||||
|
||||
isConfigValueValidMock.mockReturnValue(true);
|
||||
canSetConfigWithCurrentFunboxesMock.mockReturnValue(true);
|
||||
dbSaveConfigMock.mockResolvedValue();
|
||||
});
|
||||
expect(dispatchConfigEventMock).toHaveBeenCalledWith(
|
||||
"numbers",
|
||||
true,
|
||||
true,
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
mocks.forEach((it) => it.mockRestore());
|
||||
vi.useRealTimers();
|
||||
});
|
||||
it("triggers resize if property is set", () => {
|
||||
///WHEN
|
||||
Config.genericSet("maxLineWidth", 50, false);
|
||||
|
||||
it("cannot set if funbox disallows", () => {
|
||||
//GIVEN
|
||||
canSetConfigWithCurrentFunboxesMock.mockReturnValue(false);
|
||||
expect(miscTriggerResizeMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
//WHEN / THEN
|
||||
expect(Config.genericSet("numbers", true)).toBe(false);
|
||||
});
|
||||
it("does not triggers resize if property is not set", () => {
|
||||
///WHEN
|
||||
Config.genericSet("startGraphsAtZero", true, false);
|
||||
|
||||
it("fails if config is invalid", () => {
|
||||
//GIVEN
|
||||
isConfigValueValidMock.mockReturnValue(false);
|
||||
expect(miscTriggerResizeMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
//WHEN / THEN
|
||||
expect(Config.genericSet("numbers", "off" as any)).toBe(false);
|
||||
});
|
||||
it("does not triggers resize if property on nosave", () => {
|
||||
///WHEN
|
||||
Config.genericSet("maxLineWidth", 50, true);
|
||||
|
||||
it("dispatches event on set", () => {
|
||||
//GIVEN
|
||||
replaceConfig({ numbers: false });
|
||||
expect(miscTriggerResizeMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
//WHEN
|
||||
Config.genericSet("numbers", true, true);
|
||||
it("calls afterSet", () => {
|
||||
//GIVEN
|
||||
isDevEnvironmentMock.mockReturnValue(false);
|
||||
replaceConfig({ ads: "off" });
|
||||
|
||||
//THEN
|
||||
//WHEN
|
||||
Config.genericSet("ads", "sellout");
|
||||
|
||||
expect(dispatchConfigEventMock).toHaveBeenCalledWith(
|
||||
"numbers",
|
||||
true,
|
||||
true,
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it("saves to localstorage if nosave=false", async () => {
|
||||
//GIVEN
|
||||
replaceConfig({ numbers: false });
|
||||
|
||||
//WHEN
|
||||
Config.genericSet("numbers", true);
|
||||
|
||||
//THEN
|
||||
//wait for debounce
|
||||
await vi.advanceTimersByTimeAsync(2500);
|
||||
|
||||
//show loading
|
||||
expect(accountButtonLoadingMock).toHaveBeenNthCalledWith(1, true);
|
||||
|
||||
//save
|
||||
expect(dbSaveConfigMock).toHaveBeenCalledWith({ numbers: true });
|
||||
|
||||
//hide loading
|
||||
expect(accountButtonLoadingMock).toHaveBeenNthCalledWith(2, false);
|
||||
|
||||
//send event
|
||||
expect(dispatchConfigEventMock).toHaveBeenCalledWith(
|
||||
"saveToLocalStorage",
|
||||
expect.stringContaining("numbers")
|
||||
);
|
||||
});
|
||||
it("does not save to localstorage if nosave=true", async () => {
|
||||
//GIVEN
|
||||
|
||||
replaceConfig({ numbers: false });
|
||||
|
||||
//WHEN
|
||||
Config.genericSet("numbers", true, true);
|
||||
|
||||
//THEN
|
||||
//wait for debounce
|
||||
await vi.advanceTimersByTimeAsync(2500);
|
||||
|
||||
expect(accountButtonLoadingMock).not.toHaveBeenCalled();
|
||||
expect(dbSaveConfigMock).not.toHaveBeenCalled();
|
||||
|
||||
expect(dispatchConfigEventMock).not.toHaveBeenCalledWith(
|
||||
"saveToLocalStorage",
|
||||
expect.any(String)
|
||||
);
|
||||
});
|
||||
it("calls afterSet", () => {
|
||||
//GIVEN
|
||||
isDevEnvironmentMock.mockReturnValue(false);
|
||||
replaceConfig({ ads: "off" });
|
||||
|
||||
//WHEN
|
||||
Config.genericSet("ads", "sellout");
|
||||
|
||||
//THEN
|
||||
expect(notificationAddMock).toHaveBeenCalledWith(
|
||||
"Ad settings changed. Refreshing...",
|
||||
0
|
||||
);
|
||||
expect(miscReloadAfterMock).toHaveBeenCalledWith(3);
|
||||
});
|
||||
|
||||
it("fails if test is active and funbox no_quit", () => {
|
||||
//GIVEN
|
||||
replaceConfig({ funbox: ["no_quit"], numbers: false });
|
||||
|
||||
//WHEN
|
||||
expect(Config.genericSet("numbers", true, true)).toBe(false);
|
||||
|
||||
//THEN
|
||||
expect(notificationAddMock).toHaveBeenCalledWith(
|
||||
"No quit funbox is active. Please finish the test.",
|
||||
0,
|
||||
{
|
||||
important: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it("sends configEvents for overrideConfigs", () => {
|
||||
//GIVEN
|
||||
replaceConfig({
|
||||
confidenceMode: "off",
|
||||
freedomMode: true,
|
||||
stopOnError: "letter",
|
||||
});
|
||||
|
||||
//WHEN
|
||||
Config.genericSet("confidenceMode", "max");
|
||||
|
||||
//THEN
|
||||
expect(dispatchConfigEventMock).toHaveBeenCalledWith(
|
||||
"freedomMode",
|
||||
false,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
expect(dispatchConfigEventMock).toHaveBeenCalledWith(
|
||||
"stopOnError",
|
||||
"off",
|
||||
true,
|
||||
"letter"
|
||||
);
|
||||
|
||||
expect(dispatchConfigEventMock).toHaveBeenCalledWith(
|
||||
"confidenceMode",
|
||||
"max",
|
||||
false,
|
||||
"off"
|
||||
);
|
||||
});
|
||||
//THEN
|
||||
expect(notificationAddMock).toHaveBeenCalledWith(
|
||||
"Ad settings changed. Refreshing...",
|
||||
0
|
||||
);
|
||||
expect(miscReloadAfterMock).toHaveBeenCalledWith(3);
|
||||
});
|
||||
});
|
||||
|
||||
//TODO move the rest to schema/tests or remove after removing the setX functions from Config
|
||||
it("setMode", () => {
|
||||
expect(Config.setMode("zen")).toBe(true);
|
||||
expect(Config.setMode("invalid" as any)).toBe(false);
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
createErrorMessage,
|
||||
isObject,
|
||||
promiseWithResolvers,
|
||||
triggerResize,
|
||||
typedKeys,
|
||||
} from "./utils/misc";
|
||||
import * as ConfigSchemas from "@monkeytype/schemas/configs";
|
||||
|
@ -200,7 +201,7 @@ export function genericSet<T extends keyof ConfigSchemas.Config>(
|
|||
ConfigEvent.dispatch(key, value, nosave, previousValue);
|
||||
|
||||
if (metadata.triggerResize && !nosave) {
|
||||
$(window).trigger("resize");
|
||||
triggerResize();
|
||||
}
|
||||
|
||||
metadata.afterSet?.({ nosave: nosave || false, currentConfig: config });
|
||||
|
|
|
@ -760,4 +760,7 @@ export function sanitize<T extends z.ZodTypeAny>(
|
|||
) as z.infer<T>;
|
||||
}
|
||||
|
||||
export function triggerResize(): void {
|
||||
$(window).trigger("resize");
|
||||
}
|
||||
// DO NOT ALTER GLOBAL OBJECTSONSTRUCTOR, IT WILL BREAK RESULT HASHES
|
||||
|
|
Loading…
Add table
Reference in a new issue