Skip to content

fix: export-ignore tests/ and namespace global Document mock (#129)#53

Open
kojiromike wants to merge 2 commits into
mainfrom
export-ignore-tests
Open

fix: export-ignore tests/ and namespace global Document mock (#129)#53
kojiromike wants to merge 2 commits into
mainfrom
export-ignore-tests

Conversation

@kojiromike
Copy link
Copy Markdown
Contributor

@kojiromike kojiromike commented Jun 6, 2026

Summary

This is the cookiecutter template new OpenEMR modules are generated from, so this fix propagates to every future generated module.

Part 1 — .gitattributes export-ignore (general fix):
Excludes tests/ and dev-only paths (.github/, Dockerfile.test, compose.yml, Taskfile.yml, phpunit.xml, phpcs.xml, phpstan.neon, rector.php, .pre-commit-config.yaml, .editorconfig, cleanup.sql, DEVELOPMENT.md, GETTING_STARTED.md, release-please configs) from git archive and composer archive. Runtime paths (src/, templates/, public/, openemr.bootstrap.php, table.sql, version.php, info.txt, composer.json, LICENSE, README.md) keep shipping. Author/dev-time tooling — bin/setup, bin/precommit-template-guard.sh, tools/, and .composer-require-checker.json — is also export-ignored: authors clone the git repo (export-ignore doesn't affect clones), and the runtime CLI consumers actually invoke is bin/install-module.php, which is not ignored and still ships.

Part 2 — class_alias the global Document mock:
tests/Mocks/MockDocument.php declared class Document in the global namespace. When the module dist is installed into an openemr-internal consumer tree, whole-tree static analyzers (PHPStan, Rector) parsed this as a second definition of the real \Document, corrupting type inference.

The mock now lives at OpenCoreEMR\Modules\{ModuleName}\Tests\Mocks\MockDocument, with ?string return types mirroring the real \Document's untyped getters over nullable properties. tests/bootstrap.php class_alias()es it to \Document so code under test that does new \Document(...) still resolves. phpstan.neon gains an ignore for the global class Document for standalone analysis.

Why

Mocks under tests/ were leaking into consumer trees via the dist archive. Part 1 is the generalizing fix (consumers never parse any mock). Part 2 specifically resolves the proven-bad global Document collision in line with the sinch-fax precedent.

Precedent

Mirrors openCoreEMR/oce-module-sinch-fax#146 exactly.

Tracking issue

Refs openCoreEMR/oce-module-junction-labs#129

Test plan

  • git archive HEAD | tar -tf - excludes tests/, .github/, and dev-only files; preserves src/, public/, templates/, composer.json, LICENSE, README.md, info.txt, openemr.bootstrap.php, table.sql, version.php
  • Pre-commit hooks pass (PHPStan, PHPCS, Rector)
  • No tests/Unit/* files exist in this template yet, so no PHPUnit run is meaningful here. Validation done by checking that the rendered (post-bin/setup) {ModuleName} placeholder resolves the namespace correctly — this matches the convention already used in src/Bootstrap.php etc.

Add .gitattributes export-ignore for tests/ and dev-only paths so neither
the GitHub source tarball nor `composer archive` ships them. Move the
global-namespace MockDocument into the module's Tests\Mocks namespace and
class_alias it to \Document in tests/bootstrap.php. The phpstan.neon
ignore-list gains a `class Document` entry for standalone analysis.

This is the cookiecutter template new modules are generated from, so the
fix propagates to every future generated module. Mirrors the precedent
established in openCoreEMR/oce-module-sinch-fax#146.

Refs openCoreEMR/oce-module-junction-labs#129

Assisted-by: Claude Code
Round out the .gitattributes export-ignore set with dev/agent files that
were missed in the initial pass: .composer-require-checker.json,
.dclintrc.yaml, .yamlfmt, CLAUDE.md, bin/setup, and
bin/precommit-template-guard.sh. All are referenced only from CI hooks,
the template's one-time setup wizard, or local agent guidance — never
from runtime module code.

src/Command/SetupCommand.php is deliberately left shipping: per the
spec, src/ ships whole, and that file is meant to be removed by
bin/setup during the template's first-run customization, not pruned out
of the archive.

Refs openCoreEMR/oce-module-junction-labs#129

Assisted-by: Claude Code
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the module template to prevent test-only artifacts (especially mocks) from leaking into consumer OpenEMR trees via distribution archives, and avoids collisions with OpenEMR’s global \Document class during static analysis.

Changes:

  • Adds .gitattributes export-ignore rules to exclude tests/ and other dev-only files from git archive / composer archive.
  • Moves the Document test mock out of the global namespace into a module test namespace, and aliases it back to \Document at runtime in tests/bootstrap.php.
  • Adds a PHPStan ignore rule related to the global Document class during standalone analysis.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
tests/Mocks/MockDocument.php Namespaces the Document mock and updates return types for mock getters.
tests/bootstrap.php Adds class_alias() to map the namespaced mock to global \Document at test runtime.
phpstan.neon Adds an ignore rule for PHPStan messages involving Document during standalone analysis.
.gitattributes Introduces export-ignore rules to keep dev/test files out of archives distributed to consumers.
Comments suppressed due to low confidence (1)

tests/Mocks/MockDocument.php:104

  • get_data() is declared as ?string, but the ?? '' fallback makes it impossible to return null (and will also treat an explicitly-set null as empty string). If callers rely on null vs empty-string to distinguish “missing” content, this mock can’t currently simulate that.
    public function get_data(): ?string
    {
        if (isset($this->data['throw_exception']) && $this->data['throw_exception']) {
            throw new \Exception($this->data['exception_message'] ?? 'Document error');
        }
        return $this->data['data'] ?? '';
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .gitattributes
Comment thread .gitattributes
Comment thread tests/Mocks/MockDocument.php
Comment thread tests/Mocks/MockDocument.php
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.

2 participants