From fa31fa59a181eea1cfd5265711c70b500382f7b3 Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Sat, 8 Jun 2024 15:38:49 -0600 Subject: [PATCH] Fixed up tests --- jest.config.ts | 303 +++++++++++++-------------- src/GobanCanvas.ts | 1 - src/GobanCore.ts | 10 +- src/GobanSVG.ts | 2 - src/ScoreEstimator.ts | 3 + src/__tests__/GoEngine.test.ts | 23 +- src/__tests__/GobanCanvas.test.ts | 13 +- src/__tests__/GobanSVG.test.ts | 13 +- src/__tests__/ScoreEstimator.test.ts | 11 +- src/__tests__/autoscore.test.ts | 19 +- 10 files changed, 211 insertions(+), 187 deletions(-) diff --git a/jest.config.ts b/jest.config.ts index d68c4e62..5e88614e 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -4,206 +4,203 @@ */ export default { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "/private/var/folders/zf/nn3t1vpn1g12gm_gw4gbhnv40000gn/T/jest_dx", - - // Automatically clear mock calls, instances, contexts and results before every test - clearMocks: true, - - // Indicates whether the coverage information should be collected while executing the test - collectCoverage: true, + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/private/var/folders/zf/nn3t1vpn1g12gm_gw4gbhnv40000gn/T/jest_dx", + + // Automatically clear mock calls, instances, contexts and results before every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, - // An array of glob patterns indicating a set of files for which coverage information should be collected - collectCoverageFrom: ["/src/**"], + // An array of glob patterns indicating a set of files for which coverage information should be collected + collectCoverageFrom: ["/src/**"], - // The directory where Jest should output its coverage files - coverageDirectory: "coverage", + // The directory where Jest should output its coverage files + coverageDirectory: "coverage", - // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "/node_modules/" - // ], - coveragePathIgnorePatterns: [ - "/src/test.tsx", - "/src/goban.ts", - "/src/engine.ts", - ], + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + coveragePathIgnorePatterns: [ + "/src/test.tsx", + "/src/goban.ts", + "/src/engine.ts", + ".d.ts", + "wasm_estimator.ts", + ], - // Indicates which provider should be used to instrument code for coverage - coverageProvider: "v8", + // Indicates which provider should be used to instrument code for coverage + coverageProvider: "v8", - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], - // An object that configures minimum threshold enforcement for coverage results - coverageThreshold: { - "global": { - "lines": 60 - } - }, + // An object that configures minimum threshold enforcement for coverage results + coverageThreshold: { + global: { + lines: 60, + }, + }, - // A path to a custom dependency extractor - // dependencyExtractor: undefined, + // A path to a custom dependency extractor + // dependencyExtractor: undefined, - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, - // The default configuration for fake timers - // fakeTimers: { - // "enableGlobally": false - // }, + // The default configuration for fake timers + // fakeTimers: { + // "enableGlobally": false + // }, - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: undefined, + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, - // A set of global variables that need to be available in all test environments - // globals: {}, + // A set of global variables that need to be available in all test environments + // globals: {}, - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], - // An array of file extensions your modules use - // moduleFileExtensions: [ - // "js", - // "mjs", - // "cjs", - // "jsx", - // "ts", - // "tsx", - // "json", - // "node" - // ], + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "mjs", + // "cjs", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - // moduleNameMapper: {}, + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], - // Activates notifications for test results - // notify: false, + // Activates notifications for test results + // notify: false, - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", - // A preset that is used as a base for Jest's configuration - preset: 'ts-jest', + // A preset that is used as a base for Jest's configuration + preset: "ts-jest", - // Run tests from one or more projects - // projects: undefined, + // Run tests from one or more projects + // projects: undefined, - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, - // Automatically reset mock state before every test - // resetMocks: false, + // Automatically reset mock state before every test + // resetMocks: false, - // Reset the module registry before running each individual test - // resetModules: false, + // Reset the module registry before running each individual test + // resetModules: false, - // A path to a custom resolver - // resolver: undefined, + // A path to a custom resolver + // resolver: undefined, - // Automatically restore mock state and implementation before every test - // restoreMocks: false, + // Automatically restore mock state and implementation before every test + // restoreMocks: false, - // The root directory that Jest should scan for tests and modules within - // rootDir: undefined, + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], - // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], - // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], - // The test environment that will be used for testing - // testEnvironment: "jest-environment-node", + // The test environment that will be used for testing + // testEnvironment: "jest-environment-node", - // Options that will be passed to the testEnvironment - // testEnvironmentOptions: {}, + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, - // Adds a location field to test results - // testLocationInResults: false, + // Adds a location field to test results + // testLocationInResults: false, - // The glob patterns Jest uses to detect test files - testMatch: [ - "/src/**/__tests__/**/*.[jt]s?(x)", - "/src/**/?(*.)+(spec|test).ts" - ], + // The glob patterns Jest uses to detect test files + testMatch: ["/src/**/__tests__/**/*.[jt]s?(x)", "/src/**/?(*.)+(spec|test).ts"], - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "/node_modules/" - // ], + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, - // This option allows use of a custom test runner - // testRunner: "jest-circus/runner", + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", - // A map from regular expressions to paths to transformers - transform: { - '^.+\\.ts?$': 'ts-jest', - "^.+\\.svg$": "jest-transform-stub", - }, + // A map from regular expressions to paths to transformers + transform: { + "^.+\\.ts?$": "ts-jest", + "^.+goscorer.js$": "ts-jest", + "^.+\\.svg$": "jest-transform-stub", + }, - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - transformIgnorePatterns: [ - "/node_modules/", - ], + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + transformIgnorePatterns: ["/node_modules/"], - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, - // Indicates whether each individual test should be reported during the run - // verbose: undefined, + // Indicates whether each individual test should be reported during the run + // verbose: undefined, - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], - // Whether to use watchman for file crawling - // watchman: true, + // Whether to use watchman for file crawling + // watchman: true, - - "testTimeout": 200 + testTimeout: 200, }; diff --git a/src/GobanCanvas.ts b/src/GobanCanvas.ts index 72812ac4..338be1cd 100644 --- a/src/GobanCanvas.ts +++ b/src/GobanCanvas.ts @@ -149,7 +149,6 @@ export class GobanCanvas extends GobanCore implements GobanCanvasInterface { constructor(config: GobanCanvasConfig, preloaded_data?: AdHocFormat | JGOF) { /* TODO: Need to reconcile the clock fields before we can get rid of this `any` cast */ super(config, preloaded_data as any); - console.info("GobanCanvas created"); // console.log("Goban canvas v 0.5.74.debug 5"); // GaJ: I use this to be sure I have linked & loaded the updates if (config.board_div) { diff --git a/src/GobanCore.ts b/src/GobanCore.ts index 5130e59b..c6e85919 100644 --- a/src/GobanCore.ts +++ b/src/GobanCore.ts @@ -4104,11 +4104,15 @@ class FocusTracker { constructor() { try { if (CLIENT) { - window.addEventListener("blur", this.onBlur); - window.addEventListener("focus", this.onFocus); + try { + window.addEventListener("blur", this.onBlur); + window.addEventListener("focus", this.onFocus); + } catch (e) { + console.error(e); + } } } catch (e) { - console.error(e); + // no CLIENT defined, no problem } } diff --git a/src/GobanSVG.ts b/src/GobanSVG.ts index d711afd1..a485bde7 100644 --- a/src/GobanSVG.ts +++ b/src/GobanSVG.ts @@ -154,7 +154,6 @@ export class GobanSVG extends GobanCore implements GobanSVGInterface { constructor(config: GobanSVGConfig, preloaded_data?: AdHocFormat | JGOF) { /* TODO: Need to reconcile the clock fields before we can get rid of this `any` cast */ super(config, preloaded_data as any); - console.info("GobanSVG created"); if (config.board_div) { this.parent = config["board_div"]; @@ -1654,7 +1653,6 @@ export class GobanSVG extends GobanCore implements GobanSVGInterface { if (transparent) { cross.setAttribute("stroke-opacity", "0.6"); } - console.log("Drawing removal cross"); cell.appendChild(cross); } diff --git a/src/ScoreEstimator.ts b/src/ScoreEstimator.ts index 280ca6a9..9538cc32 100644 --- a/src/ScoreEstimator.ts +++ b/src/ScoreEstimator.ts @@ -309,6 +309,9 @@ export class ScoreEstimator { console.info("Returning autoscored_removed for getProbablyDead"); return this.autoscored_removed.map(encodeMove).join(""); } else { + // This still happens with local scoring I believe, we should probably run the autoscore + // logic for local scoring and ensure the autoscore_removed field is always set, then + // remove this probably dead code all together. console.warn("Not able to use autoscored_removed for getProbablyDead"); } diff --git a/src/__tests__/GoEngine.test.ts b/src/__tests__/GoEngine.test.ts index c0b48642..1ab224b8 100644 --- a/src/__tests__/GoEngine.test.ts +++ b/src/__tests__/GoEngine.test.ts @@ -155,14 +155,14 @@ describe("computeScore", () => { expect(engine.computeScore()).toEqual({ black: expect.objectContaining({ - scoring_positions: "aaabacadbabbbcbd", + scoring_positions: "aabaabbbacbcadbd", stones: 4, territory: 4, total: 8, }), white: expect.objectContaining({ komi: 7.5, - scoring_positions: "dadbdcddcacbcccd", + scoring_positions: "cadacbdbccdccddd", stones: 4, territory: 4, total: 15.5, @@ -188,7 +188,7 @@ describe("computeScore", () => { expect(engine.computeScore()).toEqual({ black: expect.objectContaining({ prisoners: 0, - scoring_positions: "aaabacadbabbbcbd", + scoring_positions: "aabaabbbacbcadbd", stones: 4, territory: 4, total: 8, @@ -196,7 +196,7 @@ describe("computeScore", () => { white: expect.objectContaining({ prisoners: 0, komi: 7.5, - scoring_positions: "dadbdcddcacbcccd", + scoring_positions: "cadacbdbccdccddd", stones: 4, territory: 4, total: 15.5, @@ -662,7 +662,7 @@ describe("groups", () => { expect(on_removal_updated).toBeCalledTimes(0); }); - test("toggleMetagroupRemoval empty area", () => { + test("toggleMetagroupRemoval empty area doesn't do anything", () => { const engine = new GoEngine({ width: 4, height: 2, @@ -670,20 +670,15 @@ describe("groups", () => { }); /* A B C D - * 4 x . o . - * 3 . x o . - * 2 . . o . - * 1 . . o x + * 2 x . o . + * 1 . x o . */ const on_removal_updated = jest.fn(); engine.addListener("stone-removal.updated", on_removal_updated); - expect(engine.toggleMetaGroupRemoval(0, 1)).toEqual([ - [1, [{ x: 0, y: 1 }]], - [0, []], - ]); - expect(on_removal_updated).toBeCalledTimes(1); + expect(engine.toggleMetaGroupRemoval(0, 1)).toEqual([[0, []]]); + expect(on_removal_updated).toBeCalledTimes(0); }); test("clearRemoved", () => { diff --git a/src/__tests__/GobanCanvas.test.ts b/src/__tests__/GobanCanvas.test.ts index 3596c5c9..fa67d9d6 100644 --- a/src/__tests__/GobanCanvas.test.ts +++ b/src/__tests__/GobanCanvas.test.ts @@ -312,20 +312,20 @@ describe("onTap", () => { [0, 1, 2, 0], ]); - simulateMouseClick(canvas, { x: 0, y: 0 }); + simulateMouseClick(canvas, { x: 1, y: 0 }); await expect(socket_server).toReceiveMessage( expect.arrayContaining([ "game/removed_stones/set", expect.objectContaining({ removed: true, - stones: "aaab", + stones: "babb", }), ]), ); }); - test("Shift-Clicking during stone removal toggles one stone", async () => { + test("Shift-Clicking during stone removal toggles the group", async () => { const goban = new GobanCanvas(basicScorableBoardConfig({ phase: "stone removal" })); const canvas = document.getElementById("board-canvas") as HTMLCanvasElement; @@ -338,7 +338,7 @@ describe("onTap", () => { canvas.dispatchEvent( new MouseEvent("click", { - clientX: 15, + clientX: 15 + TEST_SQUARE_SIZE, clientY: 15, shiftKey: true, }), @@ -349,7 +349,7 @@ describe("onTap", () => { "game/removed_stones/set", expect.objectContaining({ removed: true, - stones: "aa", + stones: "babb", }), ]), ); @@ -400,7 +400,7 @@ describe("onTap", () => { "game/removed_stones/set", expect.objectContaining({ removed: true, - stones: "babbbabbbbba", + stones: "babb", }), ]), ); @@ -430,6 +430,7 @@ describe("onTap", () => { SCORE_ESTIMATION_TRIALS, SCORE_ESTIMATION_TOLERANCE, false, + false, ); (goban.engine.estimateScore as jest.Mock).mockClear(); diff --git a/src/__tests__/GobanSVG.test.ts b/src/__tests__/GobanSVG.test.ts index b9e39201..df2dfef4 100644 --- a/src/__tests__/GobanSVG.test.ts +++ b/src/__tests__/GobanSVG.test.ts @@ -312,20 +312,20 @@ describe("onTap", () => { [0, 1, 2, 0], ]); - simulateMouseClick(event_layer, { x: 0, y: 0 }); + simulateMouseClick(event_layer, { x: 1, y: 0 }); await expect(socket_server).toReceiveMessage( expect.arrayContaining([ "game/removed_stones/set", expect.objectContaining({ removed: true, - stones: "aaab", + stones: "babb", }), ]), ); }); - test("Shift-Clicking during stone removal toggles one stone", async () => { + test("Shift-Clicking during stone removal toggles the group ", async () => { const goban = new GobanSVG(basicScorableBoardConfig({ phase: "stone removal" })); const event_layer = goban.event_layer; @@ -338,7 +338,7 @@ describe("onTap", () => { event_layer.dispatchEvent( new MouseEvent("click", { - clientX: 15, + clientX: 15 + TEST_SQUARE_SIZE, clientY: 15, shiftKey: true, }), @@ -349,7 +349,7 @@ describe("onTap", () => { "game/removed_stones/set", expect.objectContaining({ removed: true, - stones: "aa", + stones: "babb", }), ]), ); @@ -399,7 +399,7 @@ describe("onTap", () => { "game/removed_stones/set", expect.objectContaining({ removed: true, - stones: "babbbabbbbba", + stones: "babb", }), ]), ); @@ -429,6 +429,7 @@ describe("onTap", () => { SCORE_ESTIMATION_TRIALS, SCORE_ESTIMATION_TOLERANCE, false, + false, ); (goban.engine.estimateScore as jest.Mock).mockClear(); diff --git a/src/__tests__/ScoreEstimator.test.ts b/src/__tests__/ScoreEstimator.test.ts index 9edccd3a..d5a4b11f 100644 --- a/src/__tests__/ScoreEstimator.test.ts +++ b/src/__tests__/ScoreEstimator.test.ts @@ -66,7 +66,13 @@ describe("ScoreEstimator", () => { beforeEach(() => { set_remote_scorer(async () => { - return { ownership: OWNERSHIP, score: -7.5 }; + return { + ownership: OWNERSHIP, + score: -7.5, + autoscored_board_state: OWNERSHIP, + autoscored_removed: [], + autoscored_needs_sealing: [], + }; }); set_local_scorer(estimateScoreVoronoi); @@ -324,6 +330,9 @@ describe("ScoreEstimator", () => { set_remote_scorer(async () => ({ ownership: OWNERSHIP, + autoscored_board_state: OWNERSHIP, + autoscored_removed: [], + autoscored_needs_sealing: [], })); const se = new ScoreEstimator(undefined, engine, 10, 0.5, true); diff --git a/src/__tests__/autoscore.test.ts b/src/__tests__/autoscore.test.ts index db233b2e..4ba64d7b 100644 --- a/src/__tests__/autoscore.test.ts +++ b/src/__tests__/autoscore.test.ts @@ -30,7 +30,12 @@ describe("Auto-score tests ", () => { expect(data.correct_ownership).toBeDefined(); for (const row of data.correct_ownership) { for (const cell of row) { - const is_w_or_b = cell === "W" || cell === "B" || cell === " " || cell === "*"; + const is_w_or_b = + cell === "W" || + cell === "B" || + cell === " " || + cell === "*" || + cell === "s"; expect(is_w_or_b).toBe(true); } } @@ -49,12 +54,24 @@ describe("Auto-score tests ", () => { const v = res.result[y][x]; match &&= data.correct_ownership[y][x] === "*" || + data.correct_ownership[y][x] === "s" || (v === 0 && data.correct_ownership[y][x] === " ") || (v === 1 && data.correct_ownership[y][x] === "B") || (v === 2 && data.correct_ownership[y][x] === "W"); } } + const needs_sealing = res.needs_sealing; + /* Ensure all needs_sealing are marked as such */ + for (const { x, y } of needs_sealing) { + if (data.correct_ownership[y][x] !== "s" && data.correct_ownership[y][x] !== "*") { + console.error( + `Engine thought we needed sealing at ${x},${y} but the that spot wasn't flagged as needing it in the test file`, + ); + match = false; + } + } + expect(match).toBe(true); }); }