Skip to content

chore(tests): type-check test sources without Xcode - #142

Merged
StuBehan merged 1 commit into
mainfrom
chore/typecheck-tests
Jul 27, 2026
Merged

chore(tests): type-check test sources without Xcode#142
StuBehan merged 1 commit into
mainfrom
chore/typecheck-tests

Conversation

@StuBehan

Copy link
Copy Markdown
Collaborator

Problem

swift test needs the XCTest module, which only ships with full Xcode. On a
Command Line Tools-only machine the whole test target fails to load — so the test
sources are the one part of this repo that never gets compiled locally.

That has a concrete cost. On #139, tightening series() to require a source:
parameter broke 12 call sites in UsageHistoryTests.swift. Every production file
had been type-checked; the test file could not be, so swift test failed in CI on
a pure build error. Signature-tightening changes are exactly the ones that break
callers you cannot see.

Change

make typecheck-tests compiles the test sources in-module against the real panel
types, with XCTest swapped for stand-ins in scripts/xctest-shim.swift. Takes a
few seconds and would have caught the above before pushing.

It does not run assertions — make test and CI remain the authority on whether
tests pass. Not wired into CI, which runs the real swift test and subsumes this.

How it works

  • Test sources are staged to a temp dir with import XCTest replaced by
    import AppKit / import SwiftUI, and @testable import dropped since
    everything compiles as one module.
  • panel/main.swift is excluded so its top-level code doesn't clash; build.sh
    type-checks that file as part of the real build.
  • Warnings are suppressed: panel/ carries a stack of pre-existing macOS 14
    deprecation warnings that would bury the errors this exists to surface.
  • Diagnostics are captured and the staging paths rewritten back to
    Tests/StackNudgePanelCoreTests/, so errors name the file you actually edit
    rather than a temp dir that no longer exists.

Shim fidelity

Four details produced false errors before being fixed, all worth knowing if the
shim ever needs extending:

  • Replace import XCTest, don't delete it — XCTest re-exports Foundation, and
    several test files rely on that for Calendar / TimeZone.
  • XCTAssertEqual(_:_:accuracy:) needs its own FloatingPoint overload
    (EventListenerTests uses it).
  • XCTestCase needs setUp / tearDown / setUpWithError / tearDownWithError.
  • Those hooks must be @MainActor, matching real XCTest — otherwise a @MainActor
    test class's override becomes nonisolated and can't touch its own properties.

If the suite starts using an undeclared XCTAssert variant, the type-check fails
with "cannot find 'XCTAssertSomething' in scope"; the fix is to add the overload.

Testing

  • Passes across all 26 current test files.
  • Failure path verified by injecting the exact breakage from feat(panel): usage history graph pane #139 (a call missing
    the required source: argument): exits 1, and names
    Tests/StackNudgePanelCoreTests/… rather than the temp path.
  • bash -n and shellcheck --severity=warning clean, so the new script satisfies
    the checks CI already runs over tracked shell.
  • swift build and ./build.sh both unaffected by the new scripts/ directory —
    the shim is never compiled into the app, since both take their sources from
    panel/ and shared/ only.

@StuBehan
StuBehan merged commit 0aebf4d into main Jul 27, 2026
6 checks passed
@StuBehan
StuBehan deleted the chore/typecheck-tests branch July 27, 2026 20:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant