src/core/tests/datamodel.test.ts(2123,38): error TS2345: Argument of type '{ type: 'aux'; ident: string; equation: Equation; documentation: string; units: string; gf: GraphicalFunction | undefined; canBeModuleInput: boolean; isPublic: boolean; activeInitial: string | undefined; ... 5 more ...; connectorErrors: { ...; }[]; }' is not assignable to parameter of type 'Aux'.
src/core/tests/datamodel.test.ts(2127,40): error TS2345: Argument of type '{ type: 'stock'; ident: string; equation: Equation; documentation: string; units: string; inflows: readonly string[]; outflows: readonly string[]; nonNegative: boolean; canBeModuleInput: boolean; ... 7 more ...; connectorErrors: { ...; }[]; }' is not assignable to parameter of type 'Stock'.
src/core/tests/datamodel.test.ts(2127,59): error TS2739: Type '{ name: string; initialEquation: string; }' is missing the following properties from type 'JsonStock': inflows, outflows
src/core/tests/datamodel.test.ts(2131,39): error TS2345: Argument of type '{ type: 'flow'; ident: string; equation: Equation; documentation: string; units: string; gf: GraphicalFunction | undefined; nonNegative: boolean; canBeModuleInput: boolean; isPublic: boolean; ... 6 more ...; connectorErrors: { ...; }[]; }' is not assignable to parameter of type 'Flow'.
src/diagram/tests/build-selection-map.test.ts(9,10): error TS2305: Module '"@simlin/core/common"' has no exported member 'UID'.
src/diagram/tests/build-selection-map.test.ts(33,19): error TS2352: Conversion of type '{ selection: Set<number>; }' to type 'CanvasProps' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
src/diagram/tests/build-selection-map.test.ts(42,19): error TS2352: Conversion of type '{ selection: Set<number>; }' to type 'CanvasProps' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
src/diagram/tests/build-selection-map.test.ts(52,19): error TS2352: Conversion of type '{ selection: Set<number>; }' to type 'CanvasProps' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
src/diagram/tests/build-selection-map.test.ts(58,19): error TS2352: Conversion of type '{ selection: Set<number>; }' to type 'CanvasProps' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
src/diagram/tests/build-selection-map.test.ts(69,19): error TS2352: Conversion of type '{ selection: Set<number>; }' to type 'CanvasProps' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
src/diagram/tests/build-selection-map.test.ts(78,19): error TS2352: Conversion of type '{ selection: Set<number>; }' to type 'CanvasProps' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
src/diagram/tests/connector-routing.test.ts(33,9): error TS2322: Type '{ type: "aux"; ident: string; equation: { type: "applyToAll"; dimensionNames: string[]; equation: string; }; documentation: string; units: string; gf: undefined; data: undefined; errors: undefined; unitErrors: undefined; uid: undefined; } | { ...; }' is not assignable to type 'Aux'.
src/diagram/tests/connector-routing.test.ts(77,9): error TS2322: Type '{ type: "stock"; ident: string; equation: { type: "applyToAll"; dimensionNames: string[]; equation: string; }; documentation: string; units: string; inflows: never[]; outflows: never[]; nonNegative: false; data: undefined; errors: undefined; unitErrors: undefined; uid: undefined; } | { ...; }' is not assignable to type 'Stock'.
src/diagram/tests/connector-routing.test.ts(144,9): error TS2322: Type '{ type: "flow"; ident: string; equation: { type: "applyToAll"; dimensionNames: string[]; equation: string; }; documentation: string; units: string; gf: undefined; nonNegative: false; data: undefined; errors: undefined; unitErrors: undefined; uid: undefined; } | { ...; }' is not assignable to type 'Flow'.
src/diagram/tests/editor-applyPatch.test.ts(11,34): error TS2307: Cannot find module '../json-types' or its corresponding type declarations.
src/diagram/tests/editor-details-remount.test.ts(33,32): error TS2459: Module '"@simlin/core/datamodel"' declares 'JsonProject' locally, but it is not exported.
src/diagram/tests/editor-input.test.ts(187,11): error TS2367: This comparison appears to be unintentional because the types '"protobuf"' and '"json"' have no overlap.
src/diagram/tests/editor-input.test.ts(232,11): error TS2367: This comparison appears to be unintentional because the types '"protobuf"' and '"json"' have no overlap.
src/diagram/tests/editor-selection-changed.test.ts(31,32): error TS2459: Module '"@simlin/core/datamodel"' declares 'JsonProject' locally, but it is not exported.
src/diagram/tests/editor-selection-invariant.test.ts(29,32): error TS2459: Module '"@simlin/core/datamodel"' declares 'JsonProject' locally, but it is not exported.
src/diagram/tests/group-movement.test.ts(102,5): error TS2322: Type '{ type: "aux"; ident: string; equation: { type: "applyToAll"; dimensionNames: string[]; equation: string; }; documentation: string; units: string; gf: undefined; data: undefined; errors: undefined; unitErrors: undefined; uid: undefined; } | undefined' is not assignable to type 'Aux | undefined'.
src/diagram/tests/group-movement.test.ts(1591,21): error TS18048: 'newLink.arc' is possibly 'undefined'.
src/diagram/tests/group-movement.test.ts(1617,21): error TS18048: 'newLink.arc' is possibly 'undefined'.
src/diagram/tests/group-movement.test.ts(1618,21): error TS18048: 'newLink.arc' is possibly 'undefined'.
src/diagram/tests/group-movement.test.ts(1682,23): error TS18048: 'newLink.arc' is possibly 'undefined'.
src/diagram/tests/group-movement.test.ts(1718,23): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
src/diagram/tests/group-movement.test.ts(1743,23): error TS18048: 'newLink.arc' is possibly 'undefined'.
src/diagram/tests/hosted-web-editor-shell.test.tsx(141,60): error TS2493: Tuple type '[]' of length '0' has no element at index '1'.
src/diagram/tests/module-creation.test.ts(17,3): error TS2739: Type '{ type: "module"; ident: string; modelName: string; documentation: string; units: string; references: never[]; data: undefined; errors: undefined; unitErrors: undefined; uid: undefined; }' is missing the following properties from type 'Module': canBeModuleInput, isPublic, dataSource
src/diagram/tests/module-creation.test.ts(32,3): error TS2739: Type '{ type: "stock"; ident: string; equation: { type: "scalar"; equation: string; }; documentation: string; units: string; inflows: never[]; outflows: never[]; nonNegative: false; data: undefined; errors: undefined; unitErrors: undefined; uid: undefined; }' is missing the following properties from type 'Stock': canBeModuleInput, isPublic, activeInitial, dataSource
src/diagram/tests/module-creation.test.ts(49,3): error TS2739: Type '{ type: "aux"; ident: string; equation: { type: "scalar"; equation: string; }; documentation: string; units: string; gf: undefined; data: undefined; errors: undefined; unitErrors: undefined; uid: undefined; }' is missing the following properties from type 'Aux': canBeModuleInput, isPublic, activeInitial, dataSource
src/diagram/tests/module-creation.test.ts(64,3): error TS2739: Type '{ type: "flow"; ident: string; equation: { type: "scalar"; equation: string; }; documentation: string; units: string; gf: undefined; nonNegative: false; data: undefined; errors: undefined; unitErrors: undefined; uid: undefined; }' is missing the following properties from type 'Flow': canBeModuleInput, isPublic, activeInitial, dataSource
src/diagram/tests/module-details-utils.test.ts(21,3): error TS2322: Type '{ activeInitial?: string | undefined; dataSource?: DataSource | undefined; connectorErrors?: readonly ConnectorError[] | undefined; type: "aux"; ident: string; equation: Equation; ... 8 more ...; uid: number | undefined; }' is not assignable to type 'Aux'.
src/diagram/tests/module-details-utils.test.ts(39,3): error TS2322: Type '{ activeInitial?: string | undefined; dataSource?: DataSource | undefined; connectorErrors?: readonly ConnectorError[] | undefined; type: "stock"; ident: string; equation: Equation; ... 10 more ...; uid: number | undefined; }' is not assignable to type 'Stock'.
src/diagram/tests/module-wiring-ui.test.tsx(16,3): error TS2322: Type '{ activeInitial?: string | undefined; dataSource?: DataSource | undefined; connectorErrors?: readonly ConnectorError[] | undefined; type: "aux"; ident: string; equation: Equation; ... 8 more ...; uid: number | undefined; }' is not assignable to type 'Aux'.
src/diagram/tests/module-wiring-ui.test.tsx(34,3): error TS2322: Type '{ activeInitial?: string | undefined; dataSource?: DataSource | undefined; connectorErrors?: readonly ConnectorError[] | undefined; type: "stock"; ident: string; equation: Equation; ... 10 more ...; uid: number | undefined; }' is not assignable to type 'Stock'.
src/diagram/tests/module-wiring-ui.test.tsx(54,3): error TS2322: Type '{ activeInitial?: string | undefined; dataSource?: DataSource | undefined; connectorErrors?: readonly ConnectorError[] | undefined; type: "flow"; ident: string; equation: Equation; ... 9 more ...; uid: number | undefined; }' is not assignable to type 'Flow'.
src/diagram/tests/project-controller.test.ts(349,23): error TS2352: Conversion of type '{ elements: never[]; nextUid: number; viewBox: { x: number; y: number; width: number; height: number; }; zoom: number; }' to type 'StockFlowView' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
src/diagram/tests/snackbar.test.tsx(206,13): error TS2322: Type '{ ref: RefObject<ReRenderWrapperHandle | null>; }' is not assignable to type 'Omit<Record<string, never>, "ref">'.
src/diagram/tests/snackbar.test.tsx(263,13): error TS2322: Type '{ ref: RefObject<DurationWrapperHandle | null>; }' is not assignable to type 'Omit<Record<string, never>, "ref">'.
src/diagram/tests/snackbar.test.tsx(318,13): error TS2322: Type '{ ref: RefObject<MessageWrapperHandle | null>; }' is not assignable to type 'Omit<Record<string, never>, "ref">'.
src/diagram/tests/snackbar.test.tsx(422,35): error TS2322: Type '{ ref: RefObject<DupHostHandle | null>; }' is not assignable to type 'Omit<Record<string, never>, "ref">'.
src/diagram/tests/text-field.test.tsx(83,37): error TS2353: Object literal may only specify known properties, and ''data-testid'' does not exist in type 'InputHTMLAttributes<HTMLInputElement>'.
src/diagram/tests/variable-details-cancel.test.tsx(50,3): error TS2322: Type '{ canBeModuleInput?: boolean | undefined; isPublic?: boolean | undefined; activeInitial?: string | undefined; dataSource?: DataSource | undefined; connectorErrors?: readonly ConnectorError[] | undefined; ... 9 more ...; uid: number | undefined; }' is not assignable to type 'Aux'.
src/diagram/tests/variable-details-latex.test.tsx(31,3): error TS2739: Type '{ type: "aux"; ident: string; equation: { type: "scalar"; equation: string; }; documentation: string; units: string; gf: undefined; data: undefined; errors: undefined; unitErrors: undefined; uid: undefined; }' is missing the following properties from type 'Aux': canBeModuleInput, isPublic, activeInitial, dataSource
src/diagram/tests/variable-details-newline.test.tsx(39,3): error TS2322: Type '{ canBeModuleInput?: boolean | undefined; isPublic?: boolean | undefined; activeInitial?: string | undefined; dataSource?: DataSource | undefined; connectorErrors?: readonly ConnectorError[] | undefined; ... 9 more ...; uid: number | undefined; }' is not assignable to type 'Aux'.
src/diagram/tests/variable-details-preview.test.tsx(27,3): error TS2322: Type '{ canBeModuleInput?: boolean | undefined; isPublic?: boolean | undefined; activeInitial?: string | undefined; dataSource?: DataSource | undefined; connectorErrors?: readonly ConnectorError[] | undefined; ... 9 more ...; uid: number | undefined; }' is not assignable to type 'Aux'.
src/engine/tests/api.test.ts(797,27): error TS2739: Type '{ name: string; initialEquation: string; }' is missing the following properties from type 'JsonStock': inflows, outflows
src/engine/tests/cleanup.test.ts(41,3): error TS2741: Property 'projectRenderPng' is missing in type '{ init: () => Promise<void>; isInitialized: () => true; reset: () => Promise<void>; configureWasm: () => void; projectOpenXmile: () => Promise<ProjectHandle>; projectOpenProtobuf: () => Promise<...>; ... 33 more ...; simGetLinks: () => Promise<...>; }' but required in type 'EngineBackend'.
src/engine/tests/direct-backend.test.ts(492,63): error TS2345: Argument of type '{ models: { name: string; ops: { type: 'upsertView'; payload: { index: number; view: { elements: ({ type: string; uid: number; name: string; x: number; y: number; labelSide: string; points?: undefined; flowUid?: undefined; fromUid?: undefined; toUid?: undefined; arc?: undefined; } | { ...; } | { ...; } | { ...; })[]...' is not assignable to parameter of type 'JsonProjectPatch'.
src/engine/tests/integration.test.ts(13,27): error TS6133: 'SimlinJsonFormat' is declared but its value is never read.
src/engine/tests/race.test.ts(114,45): error TS2345: Argument of type '{ models: { name: string; ops: { type: string; payload: { aux: { name: string; equation: string; }; }; }[]; }[]; }' is not assignable to parameter of type 'JsonProjectPatch'.
src/engine/tests/wasm-model.test.ts(18,19): error TS6133: 'Model' is declared but its value is never read.
src/engine/tests/worker-backend.test.ts(13,43): error TS6196: 'SimHandle' is declared but never used.
src/engine/tests/worker-server.test.ts(166,9): error TS6133: 'server' is declared but its value is never read.
Problem
No test file in the repo is type-checked.
tsconfig.base.jsonsets"isolatedModules": true, which made ts-jest run transpile-only for every package, so type errors undertests/were silently ignored. The migration to Rstest (swc-based) does not change this -- swc also strips types without checking them -- so nothing was lost in that migration, but the hole is now explicit and worth closing.Four packages (
core,engine,diagram,app) explicitly exclude tests from their tsc program:src/core/tsconfig.json->"exclude": ["lib", "lib.module", "tests"]src/engine/tsconfig.json->"exclude": [..., "tests", ...](and@simlin/engineis not even in the roottscscript's--filterlist)src/diagram/tsconfig.json->"exclude": ["lib", "lib.browser", "tests"]src/app/tsconfig.json->"exclude": [..., "../**/tests/**", "../**/*.test.ts", ...]Two packages (
@simlin/server,@simlin/serve-web) do type-check their tests today, but only incidentally: their tsconfigincludeglobs happen to cover the test files, sopnpm tscpicks them up.Proof the hole is real
All of these currently compile clean, because nobody looks:
src/diagram/tests/editor-applyPatch.test.ts:11importsJsonProjectPatchfrom'../json-types'-- that module does not exist. The import survives because it is type-only and gets elided.src/diagram/tests/build-selection-map.test.ts:9importsUIDfrom'@simlin/core/common';UIDis actually declared in@simlin/core/datamodel.src/diagram/tests/editor-details-remount.test.ts:33(andeditor-selection-changed,editor-selection-invariant):Module '"@simlin/core/datamodel"' declares 'JsonProject' locally, but it is not exported.src/engine/tests/cleanup.test.ts:41: the fakeEngineBackendis missingprojectRenderPng-- the interface drifted and the fake never followed.Why it matters
Type-checking tests catches real bugs. While preparing the Rstest migration, the two packages that do get checked immediately surfaced 9 wrong
rs.fn<Return, Args>()calls insrc/simlin-serve/web/src/ws.test.ts: jest'sMockgeneric is the return type, whereas rstest's is the whole function signature. Those mocks ran fine but were silently mistyped. The other four packages would have hidden the same class of error, and did hide the four above.Beyond catching bugs, an unchecked test suite lets fixtures drift out of sync with the types they claim to construct -- see the
TS2739 missing fixture propscluster below, where test fixtures no longer satisfyAux/Stock/Flow/Module.Components affected
src/core,src/engine,src/diagram,src/app(unchecked);src/server,src/simlin-serve/web(checked only incidentally); repo-roottsconfig.base.jsonand the roottscscript.Scope: 55 errors across 25 files
Worst offenders:
src/diagram/tests/group-movement.test.tssrc/diagram/tests/build-selection-map.test.tssrc/diagram/tests/snackbar.test.tsxsrc/diagram/tests/module-creation.test.tssrc/core/tests/datamodel.test.tsBy error kind: TS2322 (16), TS2345 (9), TS6133 unused (7), TS2739 missing fixture props (7), TS2352 bad casts (7), TS18048 possibly-undefined (5), TS2459/TS2305/TS2307 wrong imports (5), misc (rest).
Proposed fix
Add a repo-root
tsconfig.tests.jsonand wire it into the roottscscript (pnpm exec tsc --noEmit -p tsconfig.tests.json), plus add@types/nodeto root devDependencies.Key options and why:
./tsconfig.base.json,noEmit: truecomposite: false,declaration: false,declarationMap: false-- the base setscomposite: true, which forbids disabling emitmodule: "esnext"-- needed becauseimport ... with { rstest: 'importActual' }import attributes are only allowed when targeting ES moduleslib: ["es2020","dom","dom.iterable","esnext.disposable"]-- the union of what the packages declaretypes: ["node"]pathsmirroring each package's own mapping, so tests drive sources rather than built outputincludemust list the four ambient declaration files (src/app/css-modules.d.ts,src/app/globals.d.ts,src/diagram/css-modules.d.ts,src/diagram/globals.d.ts) plus each package's test globs -- a tests-only program does not otherwise pick up the ambient CSS-module shapesThis configuration is verified working: it is what produced the error list below.
Full proposed
tsconfig.tests.json{ // Rstest compiles test files with swc, which strips types without checking // them -- ts-jest used to type-check them as a side effect of transpiling. // This program exists only to type-check every package's tests (and the // sources they pull in). It emits nothing; each package still builds with its // own tsconfig. "extends": "./tsconfig.base.json", "compilerOptions": { "noEmit": true, // "composite" (inherited) forbids disabling emit, and declarations are // meaningless for a check-only pass. "composite": false, "declaration": false, "declarationMap": false, // Partial mocks reach the unmocked module through // `import ... with { rstest: 'importActual' }`, and import attributes are // only allowed when targeting ES modules. Nothing is emitted here, so this // affects checking only. "module": "esnext", // The union of what the packages declare: DOM for the React tests, // esnext.disposable for the engine's `using` blocks. "lib": ["es2020", "dom", "dom.iterable", "esnext.disposable"], "types": ["node"], // Mirrors each package's own resolution: tests drive engine/core sources // rather than built output, and the engine's two platform-specific // specifiers resolve to their Node flavors. Relative to this file. "paths": { "@simlin/engine/internal/wasm": ["./src/engine/src/internal/wasm.node.ts"], "@simlin/engine/internal/backend-factory": ["./src/engine/src/backend-factory.node.ts"], "@simlin/engine": ["./src/engine/src/index.ts"], "@simlin/engine/*": ["./src/engine/src/*"], "@simlin/*": ["./src/*"] } }, "include": [ // Ambient declarations the sources under test rely on (CSS-module shapes). // A tests-only program does not otherwise pick these up. "src/app/css-modules.d.ts", "src/app/globals.d.ts", "src/diagram/css-modules.d.ts", "src/diagram/globals.d.ts", "src/core/tests/**/*.ts", "src/engine/tests/**/*.ts", "src/server/tests/**/*.ts", "src/server/seshcookie/**/*.test.ts", "src/app/tests/**/*.ts", "src/app/tests/**/*.tsx", "src/diagram/tests/**/*.ts", "src/diagram/tests/**/*.tsx", "src/simlin-serve/web/src/**/*.test.ts", "src/simlin-serve/web/src/**/*.test.tsx", "src/simlin-serve/web/src/test-utils/**/*.ts", "src/simlin-serve/web/src/test-utils/**/*.tsx" ] }Full error list (55)
Sequencing note
Fixing the 55 errors is separable from landing the config: the config can go in first with the four packages' test globs added incrementally (server + serve-web are already clean), or the errors can be fixed first and the config landed as the guard that keeps them fixed. The latter is preferable -- a
tsconfig.tests.jsonthat is not wired into a greenpnpm tscprovides no protection.Related
core: tsconfig.json excludes test files, breaking eslint) shares a root cause:src/core's tsconfig excludestests. That issue is scoped to eslint'sparserOptions.projectfailing to find test files; this one is abouttscnever checking them. A repo-root tests program may resolve both, and they should be fixed together.docs/tech-debt.mdentry 57 (Stale @system-dynamics/* import path in build-selection-map.test.ts) is a single instance of this class -- a dangling type-only module specifier that survives because nothing resolves it. The import path has since been updated to@simlin/core/..., but the file still names a member (UID) the module does not export, so the underlying bug outlived the partial fix. This issue subsumes entry 57.Context
Identified while preparing the Jest -> Rstest test-runner migration, when the two incidentally-checked packages surfaced mistyped
rs.fngenerics that the other four would have hidden.