com.wallstop-studios.dxmessaging 2.1.5 → 2.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.artifacts/SourceGenerators.Tests/obj/Debug/net9.0/WallstopStudios.DxMessaging.SourceGenerators.Tests.AssemblyInfo.cs +1 -1
- package/.cspell.json +4 -1
- package/.github/workflows/actionlint.yml +11 -1
- package/.github/workflows/csharpier-autofix.yml +34 -3
- package/.github/workflows/dotnet-tests.yml +13 -0
- package/.github/workflows/format-on-demand.yml +38 -44
- package/.github/workflows/json-format-check.yml +24 -0
- package/.github/workflows/lint-doc-links.yml +13 -0
- package/.github/workflows/markdown-json.yml +21 -4
- package/.github/workflows/markdown-link-text-check.yml +10 -0
- package/.github/workflows/markdown-link-validity.yml +10 -0
- package/.github/workflows/markdownlint.yml +7 -5
- package/.github/workflows/prettier-autofix.yml +67 -11
- package/.github/workflows/release-drafter.yml +2 -2
- package/.github/workflows/sync-wiki.yml +3 -3
- package/.github/workflows/yaml-format-lint.yml +26 -0
- package/.llm/context.md +113 -3
- package/.llm/skills/documentation/changelog-management.md +38 -0
- package/.llm/skills/documentation/documentation-style-guide.md +18 -0
- package/.llm/skills/documentation/documentation-update-workflow.md +2 -0
- package/.llm/skills/documentation/documentation-updates.md +2 -0
- package/.llm/skills/documentation/markdown-compatibility.md +476 -0
- package/.llm/skills/documentation/mermaid-theming.md +326 -0
- package/.llm/skills/documentation/mkdocs-navigation.md +290 -0
- package/.llm/skills/github-actions/git-renormalize-patterns.md +231 -0
- package/.llm/skills/github-actions/workflow-consistency.md +346 -0
- package/.llm/skills/index.md +53 -27
- package/.llm/skills/scripting/javascript-code-quality.md +417 -0
- package/.llm/skills/scripting/regex-documentation.md +461 -0
- package/.llm/skills/scripting/shell-best-practices.md +55 -4
- package/.llm/skills/scripting/validation-patterns.md +418 -0
- package/.llm/skills/specification.md +4 -1
- package/.llm/skills/testing/test-code-quality.md +243 -0
- package/.llm/skills/testing/test-production-code.md +348 -0
- package/CHANGELOG.md +11 -0
- package/README.md +0 -11
- package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef +1 -6
- package/Tests/Runtime/Integrations/Reflex/WallstopStudios.DxMessaging.Tests.Runtime.Reflex.asmdef +1 -1
- package/Tests/Runtime/Integrations/VContainer/WallstopStudios.DxMessaging.Tests.Runtime.VContainer.asmdef +1 -1
- package/Tests/Runtime/Integrations/Zenject/WallstopStudios.DxMessaging.Tests.Runtime.Zenject.asmdef +1 -1
- package/coverage/clover.xml +216 -3
- package/coverage/clover.xml.meta +7 -7
- package/coverage/coverage-final.json +2 -1
- package/coverage/coverage-final.json.meta +7 -7
- package/coverage/lcov-report/base.css.meta +1 -1
- package/coverage/lcov-report/block-navigation.js.meta +1 -1
- package/coverage/lcov-report/favicon.png.meta +1 -1
- package/coverage/lcov-report/index.html +25 -10
- package/coverage/lcov-report/index.html.meta +7 -7
- package/coverage/lcov-report/prettify.css.meta +1 -1
- package/coverage/lcov-report/prettify.js.meta +1 -1
- package/coverage/lcov-report/sort-arrow-sprite.png.meta +1 -1
- package/coverage/lcov-report/sorter.js.meta +1 -1
- package/coverage/lcov-report/transform-docs-to-wiki.js.html +1 -1
- package/coverage/lcov-report/transform-docs-to-wiki.js.html.meta +7 -7
- package/coverage/lcov-report/vendor.meta +1 -1
- package/coverage/lcov-report.meta +8 -8
- package/coverage/lcov.info +365 -0
- package/coverage/lcov.info.meta +7 -7
- package/docs/architecture/design-and-architecture.md +0 -1
- package/docs/concepts/index.md +37 -0
- package/docs/concepts/index.md.meta +7 -0
- package/docs/concepts/interceptors-and-ordering.md +0 -2
- package/docs/concepts/mental-model.md +390 -0
- package/docs/concepts/mental-model.md.meta +7 -0
- package/docs/concepts/message-types.md +0 -1
- package/docs/getting-started/getting-started.md +1 -0
- package/docs/getting-started/index.md +6 -5
- package/docs/getting-started/overview.md +1 -0
- package/docs/getting-started/quick-start.md +2 -1
- package/docs/getting-started/visual-guide.md +4 -10
- package/docs/hooks.py +10 -1
- package/docs/images/DxMessaging-banner.svg +1 -1
- package/docs/index.md +7 -7
- package/docs/javascripts/mermaid-config.js +44 -4
- package/docs/reference/helpers.md +130 -154
- package/docs/reference/quick-reference.md +5 -1
- package/docs/reference/reference.md +124 -130
- package/mkdocs.yml +2 -0
- package/package.json +1 -1
- package/scripts/__tests__/generate-skills-index.test.js +397 -0
- package/scripts/__tests__/generate-skills-index.test.js.meta +7 -0
- package/scripts/__tests__/mermaid-config.test.js +467 -0
- package/scripts/__tests__/mermaid-config.test.js.meta +7 -0
- package/scripts/__tests__/validate-skills-optional-fields.test.js +1474 -0
- package/scripts/__tests__/validate-skills-optional-fields.test.js.meta +7 -0
- package/scripts/__tests__/validate-skills-required-fields.test.js +188 -0
- package/scripts/__tests__/validate-skills-required-fields.test.js.meta +7 -0
- package/scripts/__tests__/validate-skills-tags.test.js +353 -0
- package/scripts/__tests__/validate-skills-tags.test.js.meta +7 -0
- package/scripts/__tests__/validate-workflows.test.js +188 -0
- package/scripts/__tests__/validate-workflows.test.js.meta +7 -0
- package/scripts/generate-skills-index.js +88 -3
- package/scripts/validate-skills.js +230 -30
- package/scripts/validate-workflows.js +272 -0
- package/scripts/validate-workflows.js.meta +7 -0
- package/site/404.html +1 -1
- package/site/advanced/emit-shorthands/index.html +2 -2
- package/site/advanced/message-bus-providers/index.html +2 -2
- package/site/advanced/registration-builders/index.html +2 -2
- package/site/advanced/runtime-configuration/index.html +2 -2
- package/site/advanced/string-messages/index.html +2 -2
- package/site/advanced.meta +1 -1
- package/site/architecture/comparisons/index.html +2 -2
- package/site/architecture/design-and-architecture/index.html +2 -2
- package/site/architecture/performance/index.html +1 -1
- package/site/architecture.meta +1 -1
- package/site/concepts/index.html +1 -0
- package/site/concepts/index.html.meta +7 -0
- package/site/concepts/interceptors-and-ordering/index.html +4 -4
- package/site/concepts/listening-patterns/index.html +2 -2
- package/site/concepts/mental-model/index.html +146 -0
- package/site/concepts/mental-model/index.html.meta +7 -0
- package/site/concepts/mental-model.meta +8 -0
- package/site/concepts/message-types/index.html +2 -2
- package/site/concepts/targeting-and-context/index.html +2 -2
- package/site/concepts.meta +1 -1
- package/site/examples/end-to-end/index.html +2 -2
- package/site/examples/end-to-end-scene-transitions/index.html +2 -2
- package/site/examples.meta +1 -1
- package/site/getting-started/getting-started/index.html +3 -3
- package/site/getting-started/index.html +4 -4
- package/site/getting-started/install/index.html +3 -3
- package/site/getting-started/overview/index.html +2 -2
- package/site/getting-started/quick-start/index.html +2 -2
- package/site/getting-started/visual-guide/index.html +11 -11
- package/site/getting-started.meta +1 -1
- package/site/guides/advanced/index.html +2 -2
- package/site/guides/diagnostics/index.html +2 -2
- package/site/guides/migration-guide/index.html +2 -2
- package/site/guides/patterns/index.html +2 -2
- package/site/guides/testing/index.html +2 -2
- package/site/guides/unity-integration/index.html +2 -2
- package/site/guides.meta +1 -1
- package/site/hooks.py.meta +1 -1
- package/site/images/DxMessaging-banner.svg +119 -0
- package/site/images/DxMessaging-banner.svg.meta +7 -0
- package/site/images.meta +8 -0
- package/site/index.html +2 -2
- package/site/integrations/index.html +2 -2
- package/site/integrations/reflex/index.html +2 -2
- package/site/integrations/vcontainer/index.html +2 -2
- package/site/integrations/zenject/index.html +2 -2
- package/site/integrations.meta +1 -1
- package/site/javascripts/csharp-highlight.js.meta +7 -7
- package/site/javascripts/mermaid-config.js +4 -1
- package/site/javascripts/mermaid-config.js.meta +1 -1
- package/site/javascripts.meta +1 -1
- package/site/reference/compatibility/index.html +1 -1
- package/site/reference/faq/index.html +1 -1
- package/site/reference/glossary/index.html +2 -2
- package/site/reference/helpers/index.html +15 -15
- package/site/reference/quick-reference/index.html +3 -3
- package/site/reference/reference/index.html +37 -37
- package/site/reference/troubleshooting/index.html +1 -1
- package/site/reference.meta +1 -1
- package/site/search/search_index.json +1 -1
- package/site/sitemap.xml +46 -38
- package/site/sitemap.xml.gz +0 -0
- package/site/stylesheets/extra.css.meta +1 -1
- package/site/stylesheets.meta +1 -1
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Test Production Code Directly"
|
|
3
|
+
id: "test-production-code"
|
|
4
|
+
category: "testing"
|
|
5
|
+
version: "1.0.0"
|
|
6
|
+
created: "2026-01-30"
|
|
7
|
+
updated: "2026-01-30"
|
|
8
|
+
|
|
9
|
+
source:
|
|
10
|
+
repository: "wallstop/DxMessaging"
|
|
11
|
+
files:
|
|
12
|
+
- path: "scripts/__tests__/"
|
|
13
|
+
- path: "scripts/"
|
|
14
|
+
url: "https://github.com/wallstop/DxMessaging"
|
|
15
|
+
|
|
16
|
+
tags:
|
|
17
|
+
- "testing"
|
|
18
|
+
- "anti-patterns"
|
|
19
|
+
- "code-quality"
|
|
20
|
+
- "javascript"
|
|
21
|
+
- "maintainability"
|
|
22
|
+
- "testability"
|
|
23
|
+
- "best-practices"
|
|
24
|
+
|
|
25
|
+
complexity:
|
|
26
|
+
level: "intermediate"
|
|
27
|
+
reasoning: "Requires understanding of test design principles and code architecture"
|
|
28
|
+
|
|
29
|
+
impact:
|
|
30
|
+
performance:
|
|
31
|
+
rating: "none"
|
|
32
|
+
details: "Testing patterns only; no runtime performance impact"
|
|
33
|
+
maintainability:
|
|
34
|
+
rating: "critical"
|
|
35
|
+
details: "Prevents tests from diverging from production behavior"
|
|
36
|
+
testability:
|
|
37
|
+
rating: "critical"
|
|
38
|
+
details: "Ensures tests actually verify production code correctness"
|
|
39
|
+
|
|
40
|
+
prerequisites:
|
|
41
|
+
- "Understanding of module exports and imports"
|
|
42
|
+
- "Familiarity with test isolation principles"
|
|
43
|
+
|
|
44
|
+
dependencies:
|
|
45
|
+
packages: []
|
|
46
|
+
skills:
|
|
47
|
+
- "comprehensive-test-coverage"
|
|
48
|
+
- "script-test-coverage"
|
|
49
|
+
|
|
50
|
+
applies_to:
|
|
51
|
+
languages:
|
|
52
|
+
- "JavaScript"
|
|
53
|
+
- "TypeScript"
|
|
54
|
+
- "C#"
|
|
55
|
+
frameworks:
|
|
56
|
+
- "Jest"
|
|
57
|
+
- "Node.js"
|
|
58
|
+
- "NUnit"
|
|
59
|
+
versions:
|
|
60
|
+
node: ">=18.0"
|
|
61
|
+
jest: ">=29.0"
|
|
62
|
+
|
|
63
|
+
aliases:
|
|
64
|
+
- "Test real code"
|
|
65
|
+
- "Don't re-implement in tests"
|
|
66
|
+
- "Test production directly"
|
|
67
|
+
- "Avoid test duplication"
|
|
68
|
+
|
|
69
|
+
related:
|
|
70
|
+
- "comprehensive-test-coverage"
|
|
71
|
+
- "script-test-coverage"
|
|
72
|
+
- "test-code-quality"
|
|
73
|
+
|
|
74
|
+
status: "stable"
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
# Test Production Code Directly
|
|
78
|
+
|
|
79
|
+
> **One-line summary**: Tests must import and use production code, never re-implement production logic locally.
|
|
80
|
+
|
|
81
|
+
## Overview
|
|
82
|
+
|
|
83
|
+
A common anti-pattern in testing is re-implementing production validation logic inside test files. When tests maintain their own copies of validation rules, they can pass even when production code regresses. This skill documents how to structure code for testability and avoid this dangerous pattern.
|
|
84
|
+
|
|
85
|
+
## Problem Statement
|
|
86
|
+
|
|
87
|
+
### The Anti-Pattern
|
|
88
|
+
|
|
89
|
+
Tests that re-implement production logic create a false sense of security:
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
// PRODUCTION: scripts/validate-data.js
|
|
93
|
+
function validateRecord(record) {
|
|
94
|
+
const errors = [];
|
|
95
|
+
if (!record.name || record.name.length < 3) {
|
|
96
|
+
errors.push("Name must be at least 3 characters");
|
|
97
|
+
}
|
|
98
|
+
if (!record.email || !record.email.includes("@")) {
|
|
99
|
+
errors.push("Email must be valid");
|
|
100
|
+
}
|
|
101
|
+
return errors;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// TEST: scripts/__tests__/validate-data.test.js
|
|
105
|
+
// WRONG: Re-implementing validation locally
|
|
106
|
+
function localValidateRecord(record) {
|
|
107
|
+
const errors = [];
|
|
108
|
+
if (!record.name || record.name.length < 3) {
|
|
109
|
+
// Duplicated logic!
|
|
110
|
+
errors.push("Name must be at least 3 characters");
|
|
111
|
+
}
|
|
112
|
+
if (!record.email || !record.email.includes("@")) {
|
|
113
|
+
// Duplicated logic!
|
|
114
|
+
errors.push("Email must be valid");
|
|
115
|
+
}
|
|
116
|
+
return errors;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
test("should validate record correctly", () => {
|
|
120
|
+
const result = localValidateRecord({ name: "Jo", email: "bad" });
|
|
121
|
+
expect(result).toHaveLength(2); // Tests pass, but production untested!
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Why This Is Dangerous
|
|
126
|
+
|
|
127
|
+
1. **Production regressions go undetected**: If someone changes `< 3` to `< 2` in production, tests still pass because they use the local copy.
|
|
128
|
+
1. **Maintenance burden doubles**: Every production change requires updating test copies.
|
|
129
|
+
1. **Divergence over time**: Local test copies gradually drift from production reality.
|
|
130
|
+
1. **False confidence**: 100% test coverage means nothing if tests don't exercise production code.
|
|
131
|
+
1. **Bug duplication**: If the same bug exists in both copies, tests won't catch it.
|
|
132
|
+
|
|
133
|
+
## Solution
|
|
134
|
+
|
|
135
|
+
### Structure Production Code for Testability
|
|
136
|
+
|
|
137
|
+
Export validation functions and helper logic so tests can import them:
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
// PRODUCTION: scripts/validate-data.js
|
|
141
|
+
/**
|
|
142
|
+
* Validates a record and returns any errors.
|
|
143
|
+
* @param {Object} record - The record to validate
|
|
144
|
+
* @returns {string[]} Array of error messages
|
|
145
|
+
*/
|
|
146
|
+
function validateRecord(record) {
|
|
147
|
+
const errors = [];
|
|
148
|
+
if (!isValidName(record.name)) {
|
|
149
|
+
errors.push("Name must be at least 3 characters");
|
|
150
|
+
}
|
|
151
|
+
if (!isValidEmail(record.email)) {
|
|
152
|
+
errors.push("Email must be valid");
|
|
153
|
+
}
|
|
154
|
+
return errors;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Validates name length.
|
|
159
|
+
* @param {string} name - The name to validate
|
|
160
|
+
* @returns {boolean} True if valid
|
|
161
|
+
*/
|
|
162
|
+
function isValidName(name) {
|
|
163
|
+
return name && name.length >= 3;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Validates email format.
|
|
168
|
+
* @param {string} email - The email to validate
|
|
169
|
+
* @returns {boolean} True if valid
|
|
170
|
+
*/
|
|
171
|
+
function isValidEmail(email) {
|
|
172
|
+
return email && email.includes("@");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Export everything tests need
|
|
176
|
+
module.exports = {
|
|
177
|
+
validateRecord,
|
|
178
|
+
isValidName,
|
|
179
|
+
isValidEmail
|
|
180
|
+
};
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Test Production Code Directly
|
|
184
|
+
|
|
185
|
+
Import and test the actual production functions:
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
// TEST: scripts/__tests__/validate-data.test.js
|
|
189
|
+
// CORRECT: Import production code
|
|
190
|
+
const { validateRecord, isValidName, isValidEmail } = require("../validate-data");
|
|
191
|
+
|
|
192
|
+
describe("validateRecord", () => {
|
|
193
|
+
test("should return no errors for valid record", () => {
|
|
194
|
+
const result = validateRecord({ name: "John", email: "john@example.com" });
|
|
195
|
+
expect(result).toHaveLength(0);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test("should return error for short name", () => {
|
|
199
|
+
const result = validateRecord({ name: "Jo", email: "john@example.com" });
|
|
200
|
+
expect(result).toContain("Name must be at least 3 characters");
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("should return error for invalid email", () => {
|
|
204
|
+
const result = validateRecord({ name: "John", email: "invalid" });
|
|
205
|
+
expect(result).toContain("Email must be valid");
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe("isValidName", () => {
|
|
210
|
+
test("should accept names with 3 or more characters", () => {
|
|
211
|
+
expect(isValidName("Joe")).toBe(true);
|
|
212
|
+
expect(isValidName("John")).toBe(true);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test("should reject names with fewer than 3 characters", () => {
|
|
216
|
+
expect(isValidName("Jo")).toBe(false);
|
|
217
|
+
expect(isValidName("J")).toBe(false);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("should reject null and undefined", () => {
|
|
221
|
+
expect(isValidName(null)).toBe(false);
|
|
222
|
+
expect(isValidName(undefined)).toBe(false);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## When Local Test Helpers Are Acceptable
|
|
228
|
+
|
|
229
|
+
Not all code in test files is duplication. These are legitimate uses:
|
|
230
|
+
|
|
231
|
+
### Thin Wrappers for Test Convenience
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
// ACCEPTABLE: Thin wrapper that delegates to production
|
|
235
|
+
function validateAndExpectErrors(record, expectedCount) {
|
|
236
|
+
const result = validateRecord(record); // Calls production!
|
|
237
|
+
expect(result).toHaveLength(expectedCount);
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Test-Only Utilities
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
// ACCEPTABLE: Test data generators
|
|
246
|
+
function createValidRecord(overrides = {}) {
|
|
247
|
+
return {
|
|
248
|
+
name: "Default Name",
|
|
249
|
+
email: "default@example.com",
|
|
250
|
+
...overrides
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ACCEPTABLE: Custom matchers
|
|
255
|
+
function expectValidationError(result, expectedMessage) {
|
|
256
|
+
expect(result.some((msg) => msg.includes(expectedMessage))).toBe(true);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// ACCEPTABLE: Factories for test data
|
|
260
|
+
const TestRecords = {
|
|
261
|
+
valid: { name: "John Doe", email: "john@example.com" },
|
|
262
|
+
invalidName: { name: "X", email: "john@example.com" }
|
|
263
|
+
};
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Handling Unavoidable Duplication
|
|
267
|
+
|
|
268
|
+
Some situations require maintaining parallel implementations. Use SYNC notes to keep them aligned.
|
|
269
|
+
|
|
270
|
+
### PowerShell Scripts with JavaScript Tests
|
|
271
|
+
|
|
272
|
+
When the production script is PowerShell but tests are JavaScript:
|
|
273
|
+
|
|
274
|
+
```powershell
|
|
275
|
+
# PRODUCTION: scripts/validate-data.ps1
|
|
276
|
+
# SYNC: Keep validation logic in sync with validate-data.test.js validateRecord()
|
|
277
|
+
function Test-Record {
|
|
278
|
+
param([hashtable]$Record)
|
|
279
|
+
$errors = @()
|
|
280
|
+
if (-not $Record.name -or $Record.name.Length -lt 3) {
|
|
281
|
+
$errors += "Name must be at least 3 characters"
|
|
282
|
+
}
|
|
283
|
+
return $errors
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
// TEST: scripts/__tests__/validate-data.test.js
|
|
289
|
+
// SYNC: Keep validation logic in sync with validate-data.ps1 Test-Record
|
|
290
|
+
function validateRecord(record) {
|
|
291
|
+
const errors = [];
|
|
292
|
+
if (!record.name || record.name.length < 3) {
|
|
293
|
+
errors += "Name must be at least 3 characters";
|
|
294
|
+
}
|
|
295
|
+
return errors;
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Browser-Only Code
|
|
300
|
+
|
|
301
|
+
When code runs only in browsers and cannot be tested in Node.js:
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
// PRODUCTION: browser-only.js (uses DOM APIs)
|
|
305
|
+
// SYNC: Core logic duplicated for testing in browser-only.test.js
|
|
306
|
+
|
|
307
|
+
// TEST: browser-only.test.js
|
|
308
|
+
// SYNC: Keep validation logic in sync with browser-only.js computeLayout()
|
|
309
|
+
// This is a test-only implementation because production uses DOM APIs
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## SYNC Note Best Practices
|
|
313
|
+
|
|
314
|
+
When duplication is unavoidable, follow these SYNC note guidelines:
|
|
315
|
+
|
|
316
|
+
1. **Always bidirectional**: Both files must reference each other
|
|
317
|
+
1. **Never use line numbers**: Reference function names, not line numbers that change
|
|
318
|
+
1. **Use descriptive identifiers**: `SYNC: Keep in sync with validate.js isValidEmail()` not `SYNC: Keep in sync with validate.js line 42`
|
|
319
|
+
1. **Verify references exist**: Confirm the referenced function exists before adding the note
|
|
320
|
+
1. **Update both on changes**: When modifying synced code, update both locations
|
|
321
|
+
|
|
322
|
+
## Red Flags to Watch For
|
|
323
|
+
|
|
324
|
+
These patterns suggest tests may not be exercising production code:
|
|
325
|
+
|
|
326
|
+
| Red Flag | Why It's Suspicious |
|
|
327
|
+
| ------------------------------------------------------ | ----------------------------- |
|
|
328
|
+
| Test file defines validation constants | Should import from production |
|
|
329
|
+
| Test file has utility functions that mirror production | Should import instead |
|
|
330
|
+
| Test never imports the module it's supposedly testing | Tests itself, not production |
|
|
331
|
+
| Test file size rivals production file size | Too much duplicated logic |
|
|
332
|
+
| Same bug exists in production and tests | Copied code with copied bugs |
|
|
333
|
+
|
|
334
|
+
## Verification Checklist
|
|
335
|
+
|
|
336
|
+
Before merging, verify tests exercise production code:
|
|
337
|
+
|
|
338
|
+
1. **Check imports**: Does the test file import from the production module?
|
|
339
|
+
1. **Check coverage**: Does production file show coverage when tests run?
|
|
340
|
+
1. **Mutation test**: Change production code slightly - do tests fail?
|
|
341
|
+
1. **Review test functions**: Are they calling production code or local copies?
|
|
342
|
+
1. **Search for duplication**: Do test and production files have similar function bodies?
|
|
343
|
+
|
|
344
|
+
## See Also
|
|
345
|
+
|
|
346
|
+
- [Comprehensive Test Coverage skill](comprehensive-test-coverage.md) - What to test
|
|
347
|
+
- [Script Test Coverage skill](script-test-coverage.md) - Testing scripts specifically
|
|
348
|
+
- [Test Code Quality skill](test-code-quality.md) - Test documentation accuracy
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.1.6]
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Concepts index page and Mental Model documentation for understanding DxMessaging's design principles
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Orphaned documentation pages in Concepts section now included in mkdocs.yml navigation
|
|
19
|
+
- Burst compiler assembly resolution errors when using DxMessaging as a package on disk and building for player platforms. Benchmarks and integration test assembly definitions now specify Editor-only platform to prevent Burst from attempting to resolve these assemblies during player builds.
|
|
20
|
+
|
|
10
21
|
## [2.1.5]
|
|
11
22
|
|
|
12
23
|
### Added
|
package/README.md
CHANGED
|
@@ -231,14 +231,6 @@ flowchart TD
|
|
|
231
231
|
Q3{Do you need observable, decoupled,<br/>lifecycle-safe messaging?}
|
|
232
232
|
Q3 -->|YES| A3["✅ Use DxMessaging"]
|
|
233
233
|
Q3 -->|NO| A4["❌ Keep it simple"]
|
|
234
|
-
|
|
235
|
-
style Q1 fill:#91d5ff,stroke:#096dd9,stroke-width:2px,color:#000
|
|
236
|
-
style Q2 fill:#91d5ff,stroke:#096dd9,stroke-width:2px,color:#000
|
|
237
|
-
style Q3 fill:#91d5ff,stroke:#096dd9,stroke-width:2px,color:#000
|
|
238
|
-
style A1 fill:#f0f0f0,stroke:#666,stroke-width:2px,color:#000
|
|
239
|
-
style A2 fill:#f0f0f0,stroke:#666,stroke-width:2px,color:#000
|
|
240
|
-
style A3 fill:#95de64,stroke:#237804,stroke-width:3px,color:#000
|
|
241
|
-
style A4 fill:#f0f0f0,stroke:#666,stroke-width:2px,color:#000
|
|
242
234
|
```
|
|
243
235
|
|
|
244
236
|
**Rule of thumb:** If you're reading this README and thinking "this could address several challenges I'm facing," then DxMessaging may be a good fit. If you're thinking "this seems complicated," start with the [Visual Guide](docs/getting-started/visual-guide.md) or stick with simpler patterns.
|
|
@@ -448,9 +440,6 @@ flowchart LR
|
|
|
448
440
|
P[Producer] --> I[Interceptors<br/>validate/mutate]
|
|
449
441
|
I --> H[Handlers<br/>main logic]
|
|
450
442
|
H --> PP[Post-Processors<br/>analytics/logging]
|
|
451
|
-
style I fill:#ffe7ba,stroke:#d48806,stroke-width:2px,color:#000
|
|
452
|
-
style H fill:#91d5ff,stroke:#096dd9,stroke-width:2px,color:#000
|
|
453
|
-
style PP fill:#b7eb8f,stroke:#389e0d,stroke-width:2px,color:#000
|
|
454
443
|
```
|
|
455
444
|
|
|
456
445
|
### Global Observers: Listen to All Events
|
package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"UniRx",
|
|
13
13
|
"UniTask"
|
|
14
14
|
],
|
|
15
|
-
"includePlatforms": [],
|
|
15
|
+
"includePlatforms": ["Editor"],
|
|
16
16
|
"excludePlatforms": [],
|
|
17
17
|
"allowUnsafeCode": false,
|
|
18
18
|
"overrideReferences": true,
|
|
@@ -35,11 +35,6 @@
|
|
|
35
35
|
"expression": "0.0.1",
|
|
36
36
|
"define": "UNIRX_PRESENT"
|
|
37
37
|
},
|
|
38
|
-
{
|
|
39
|
-
"name": "com.svermeulen.extenject",
|
|
40
|
-
"expression": "0.0.1",
|
|
41
|
-
"define": "ZENJECT_PRESENT"
|
|
42
|
-
},
|
|
43
38
|
{
|
|
44
39
|
"name": "com.svermeulen.extenject",
|
|
45
40
|
"expression": "0.0.1",
|
package/coverage/clover.xml
CHANGED
|
@@ -1,6 +1,219 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<coverage generated="
|
|
3
|
-
<project timestamp="
|
|
4
|
-
<metrics statements="
|
|
2
|
+
<coverage generated="1769731970210" clover="3.2.0">
|
|
3
|
+
<project timestamp="1769731970211" name="All files">
|
|
4
|
+
<metrics statements="210" coveredstatements="131" conditionals="116" coveredconditionals="81" methods="15" coveredmethods="11" elements="341" coveredelements="223" complexity="0" loc="210" ncloc="210" packages="1" files="1" classes="1"/>
|
|
5
|
+
<file name="transform-docs-to-wiki.js" path="/workspaces/com.wallstop-studios.dxmessaging/scripts/wiki/transform-docs-to-wiki.js">
|
|
6
|
+
<metrics statements="210" coveredstatements="131" conditionals="116" coveredconditionals="81" methods="15" coveredmethods="11"/>
|
|
7
|
+
<line num="18" count="1" type="stmt"/>
|
|
8
|
+
<line num="19" count="1" type="stmt"/>
|
|
9
|
+
<line num="21" count="1" type="stmt"/>
|
|
10
|
+
<line num="28" count="13" type="stmt"/>
|
|
11
|
+
<line num="29" count="13" type="stmt"/>
|
|
12
|
+
<line num="33" count="51" type="stmt"/>
|
|
13
|
+
<line num="34" count="51" type="stmt"/>
|
|
14
|
+
<line num="36" count="51" type="cond" truecount="2" falsecount="0"/>
|
|
15
|
+
<line num="37" count="26" type="stmt"/>
|
|
16
|
+
<line num="38" count="26" type="stmt"/>
|
|
17
|
+
<line num="40" count="26" type="cond" truecount="2" falsecount="0"/>
|
|
18
|
+
<line num="41" count="12" type="stmt"/>
|
|
19
|
+
<line num="42" count="12" type="stmt"/>
|
|
20
|
+
<line num="43" count="14" type="cond" truecount="2" falsecount="0"/>
|
|
21
|
+
<line num="47" count="11" type="stmt"/>
|
|
22
|
+
<line num="48" count="11" type="stmt"/>
|
|
23
|
+
<line num="52" count="51" type="stmt"/>
|
|
24
|
+
<line num="56" count="1" type="stmt"/>
|
|
25
|
+
<line num="57" count="1" type="stmt"/>
|
|
26
|
+
<line num="62" count="23" type="stmt"/>
|
|
27
|
+
<line num="66" count="11" type="stmt"/>
|
|
28
|
+
<line num="70" count="18" type="stmt"/>
|
|
29
|
+
<line num="72" count="18" type="cond" truecount="4" falsecount="0"/>
|
|
30
|
+
<line num="73" count="4" type="stmt"/>
|
|
31
|
+
<line num="74" count="4" type="cond" truecount="2" falsecount="0"/>
|
|
32
|
+
<line num="75" count="1" type="stmt"/>
|
|
33
|
+
<line num="80" count="17" type="cond" truecount="4" falsecount="0"/>
|
|
34
|
+
<line num="81" count="2" type="stmt"/>
|
|
35
|
+
<line num="85" count="15" type="stmt"/>
|
|
36
|
+
<line num="87" count="15" type="stmt"/>
|
|
37
|
+
<line num="89" count="23" type="stmt"/>
|
|
38
|
+
<line num="94" count="44" type="stmt"/>
|
|
39
|
+
<line num="95" count="44" type="stmt"/>
|
|
40
|
+
<line num="97" count="44" type="stmt"/>
|
|
41
|
+
<line num="98" count="261" type="cond" truecount="4" falsecount="0"/>
|
|
42
|
+
<line num="99" count="2" type="stmt"/>
|
|
43
|
+
<line num="100" count="2" type="stmt"/>
|
|
44
|
+
<line num="103" count="259" type="cond" truecount="2" falsecount="0"/>
|
|
45
|
+
<line num="109" count="14" type="stmt"/>
|
|
46
|
+
<line num="110" count="14" type="stmt"/>
|
|
47
|
+
<line num="111" count="14" type="cond" truecount="2" falsecount="0"/>
|
|
48
|
+
<line num="112" count="33" type="stmt"/>
|
|
49
|
+
<line num="113" count="33" type="stmt"/>
|
|
50
|
+
<line num="116" count="14" type="stmt"/>
|
|
51
|
+
<line num="117" count="14" type="stmt"/>
|
|
52
|
+
<line num="118" count="14" type="cond" truecount="2" falsecount="0"/>
|
|
53
|
+
<line num="119" count="9" type="stmt"/>
|
|
54
|
+
<line num="120" count="9" type="stmt"/>
|
|
55
|
+
<line num="123" count="5" type="stmt"/>
|
|
56
|
+
<line num="124" count="5" type="stmt"/>
|
|
57
|
+
<line num="128" count="245" type="cond" truecount="2" falsecount="0"/>
|
|
58
|
+
<line num="129" count="245" type="cond" truecount="4" falsecount="0"/>
|
|
59
|
+
<line num="131" count="245" type="cond" truecount="2" falsecount="0"/>
|
|
60
|
+
<line num="132" count="219" type="stmt"/>
|
|
61
|
+
<line num="133" count="219" type="stmt"/>
|
|
62
|
+
<line num="136" count="26" type="cond" truecount="2" falsecount="0"/>
|
|
63
|
+
<line num="138" count="26" type="stmt"/>
|
|
64
|
+
<line num="139" count="26" type="stmt"/>
|
|
65
|
+
<line num="140" count="26" type="stmt"/>
|
|
66
|
+
<line num="141" count="201" type="cond" truecount="2" falsecount="2"/>
|
|
67
|
+
<line num="142" count="0" type="stmt"/>
|
|
68
|
+
<line num="143" count="0" type="stmt"/>
|
|
69
|
+
<line num="145" count="201" type="cond" truecount="2" falsecount="0"/>
|
|
70
|
+
<line num="146" count="201" type="cond" truecount="2" falsecount="0"/>
|
|
71
|
+
<line num="147" count="27" type="stmt"/>
|
|
72
|
+
<line num="148" count="27" type="cond" truecount="2" falsecount="0"/>
|
|
73
|
+
<line num="149" count="26" type="stmt"/>
|
|
74
|
+
<line num="150" count="26" type="stmt"/>
|
|
75
|
+
<line num="155" count="26" type="cond" truecount="4" falsecount="1"/>
|
|
76
|
+
<line num="156" count="0" type="stmt"/>
|
|
77
|
+
<line num="157" count="0" type="stmt"/>
|
|
78
|
+
<line num="160" count="26" type="stmt"/>
|
|
79
|
+
<line num="161" count="26" type="stmt"/>
|
|
80
|
+
<line num="162" count="26" type="stmt"/>
|
|
81
|
+
<line num="163" count="26" type="stmt"/>
|
|
82
|
+
<line num="164" count="305" type="cond" truecount="2" falsecount="2"/>
|
|
83
|
+
<line num="165" count="0" type="stmt"/>
|
|
84
|
+
<line num="166" count="0" type="stmt"/>
|
|
85
|
+
<line num="168" count="305" type="cond" truecount="2" falsecount="0"/>
|
|
86
|
+
<line num="169" count="305" type="cond" truecount="2" falsecount="0"/>
|
|
87
|
+
<line num="170" count="27" type="stmt"/>
|
|
88
|
+
<line num="171" count="27" type="cond" truecount="2" falsecount="0"/>
|
|
89
|
+
<line num="172" count="26" type="stmt"/>
|
|
90
|
+
<line num="173" count="26" type="stmt"/>
|
|
91
|
+
<line num="178" count="26" type="cond" truecount="1" falsecount="1"/>
|
|
92
|
+
<line num="179" count="0" type="stmt"/>
|
|
93
|
+
<line num="180" count="0" type="stmt"/>
|
|
94
|
+
<line num="183" count="26" type="stmt"/>
|
|
95
|
+
<line num="184" count="26" type="stmt"/>
|
|
96
|
+
<line num="185" count="26" type="stmt"/>
|
|
97
|
+
<line num="187" count="26" type="stmt"/>
|
|
98
|
+
<line num="195" count="26" type="stmt"/>
|
|
99
|
+
<line num="198" count="44" type="stmt"/>
|
|
100
|
+
<line num="202" count="1" type="cond" truecount="1" falsecount="1"/>
|
|
101
|
+
<line num="203" count="0" type="stmt"/>
|
|
102
|
+
<line num="206" count="1" type="stmt"/>
|
|
103
|
+
<line num="207" count="1" type="stmt"/>
|
|
104
|
+
<line num="208" count="1" type="stmt"/>
|
|
105
|
+
<line num="209" count="1" type="stmt"/>
|
|
106
|
+
<line num="213" count="24" type="stmt"/>
|
|
107
|
+
<line num="215" count="24" type="cond" truecount="2" falsecount="0"/>
|
|
108
|
+
<line num="216" count="12" type="stmt"/>
|
|
109
|
+
<line num="219" count="12" type="stmt"/>
|
|
110
|
+
<line num="220" count="12" type="stmt"/>
|
|
111
|
+
<line num="221" count="13" type="stmt"/>
|
|
112
|
+
<line num="223" count="13" type="cond" truecount="2" falsecount="0"/>
|
|
113
|
+
<line num="224" count="2" type="stmt"/>
|
|
114
|
+
<line num="227" count="11" type="cond" truecount="2" falsecount="0"/>
|
|
115
|
+
<line num="228" count="1" type="stmt"/>
|
|
116
|
+
<line num="231" count="10" type="cond" truecount="2" falsecount="0"/>
|
|
117
|
+
<line num="232" count="1" type="stmt"/>
|
|
118
|
+
<line num="233" count="1" type="stmt"/>
|
|
119
|
+
<line num="234" count="1" type="stmt"/>
|
|
120
|
+
<line num="235" count="1" type="stmt"/>
|
|
121
|
+
<line num="238" count="9" type="stmt"/>
|
|
122
|
+
<line num="239" count="9" type="stmt"/>
|
|
123
|
+
<line num="240" count="9" type="stmt"/>
|
|
124
|
+
<line num="241" count="9" type="cond" truecount="2" falsecount="0"/>
|
|
125
|
+
<line num="242" count="1" type="stmt"/>
|
|
126
|
+
<line num="243" count="1" type="stmt"/>
|
|
127
|
+
<line num="246" count="9" type="stmt"/>
|
|
128
|
+
<line num="249" count="9" type="cond" truecount="2" falsecount="0"/>
|
|
129
|
+
<line num="250" count="1" type="stmt"/>
|
|
130
|
+
<line num="251" count="8" type="cond" truecount="4" falsecount="0"/>
|
|
131
|
+
<line num="252" count="7" type="stmt"/>
|
|
132
|
+
<line num="254" count="1" type="stmt"/>
|
|
133
|
+
<line num="257" count="9" type="stmt"/>
|
|
134
|
+
<line num="260" count="12" type="stmt"/>
|
|
135
|
+
<line num="264" count="5" type="stmt"/>
|
|
136
|
+
<line num="265" count="5" type="stmt"/>
|
|
137
|
+
<line num="266" count="5" type="stmt"/>
|
|
138
|
+
<line num="268" count="5" type="stmt"/>
|
|
139
|
+
<line num="269" count="27" type="stmt"/>
|
|
140
|
+
<line num="270" count="27" type="stmt"/>
|
|
141
|
+
<line num="272" count="27" type="cond" truecount="4" falsecount="0"/>
|
|
142
|
+
<line num="273" count="12" type="stmt"/>
|
|
143
|
+
<line num="275" count="15" type="stmt"/>
|
|
144
|
+
<line num="279" count="5" type="stmt"/>
|
|
145
|
+
<line num="283" count="0" type="stmt"/>
|
|
146
|
+
<line num="284" count="0" type="stmt"/>
|
|
147
|
+
<line num="286" count="0" type="stmt"/>
|
|
148
|
+
<line num="287" count="0" type="stmt"/>
|
|
149
|
+
<line num="288" count="0" type="cond" truecount="0" falsecount="2"/>
|
|
150
|
+
<line num="289" count="0" type="cond" truecount="0" falsecount="4"/>
|
|
151
|
+
<line num="290" count="0" type="stmt"/>
|
|
152
|
+
<line num="292" count="0" type="cond" truecount="0" falsecount="2"/>
|
|
153
|
+
<line num="293" count="0" type="stmt"/>
|
|
154
|
+
<line num="297" count="0" type="stmt"/>
|
|
155
|
+
<line num="301" count="0" type="stmt"/>
|
|
156
|
+
<line num="302" count="0" type="stmt"/>
|
|
157
|
+
<line num="304" count="0" type="stmt"/>
|
|
158
|
+
<line num="305" count="0" type="stmt"/>
|
|
159
|
+
<line num="306" count="0" type="cond" truecount="0" falsecount="2"/>
|
|
160
|
+
<line num="307" count="0" type="stmt"/>
|
|
161
|
+
<line num="309" count="0" type="stmt"/>
|
|
162
|
+
<line num="310" count="0" type="cond" truecount="0" falsecount="2"/>
|
|
163
|
+
<line num="311" count="0" type="stmt"/>
|
|
164
|
+
<line num="312" count="0" type="cond" truecount="0" falsecount="2"/>
|
|
165
|
+
<line num="313" count="0" type="stmt"/>
|
|
166
|
+
<line num="314" count="0" type="stmt"/>
|
|
167
|
+
<line num="315" count="0" type="stmt"/>
|
|
168
|
+
<line num="316" count="0" type="stmt"/>
|
|
169
|
+
<line num="317" count="0" type="stmt"/>
|
|
170
|
+
<line num="319" count="0" type="stmt"/>
|
|
171
|
+
<line num="320" count="0" type="stmt"/>
|
|
172
|
+
<line num="321" count="0" type="stmt"/>
|
|
173
|
+
<line num="325" count="0" type="stmt"/>
|
|
174
|
+
<line num="329" count="0" type="cond" truecount="0" falsecount="2"/>
|
|
175
|
+
<line num="330" count="0" type="stmt"/>
|
|
176
|
+
<line num="333" count="0" type="stmt"/>
|
|
177
|
+
<line num="334" count="0" type="cond" truecount="0" falsecount="2"/>
|
|
178
|
+
<line num="335" count="0" type="stmt"/>
|
|
179
|
+
<line num="338" count="0" type="stmt"/>
|
|
180
|
+
<line num="339" count="0" type="stmt"/>
|
|
181
|
+
<line num="341" count="0" type="stmt"/>
|
|
182
|
+
<line num="342" count="0" type="stmt"/>
|
|
183
|
+
<line num="343" count="0" type="stmt"/>
|
|
184
|
+
<line num="344" count="0" type="stmt"/>
|
|
185
|
+
<line num="345" count="0" type="stmt"/>
|
|
186
|
+
<line num="347" count="0" type="cond" truecount="0" falsecount="2"/>
|
|
187
|
+
<line num="348" count="0" type="stmt"/>
|
|
188
|
+
<line num="349" count="0" type="stmt"/>
|
|
189
|
+
<line num="352" count="0" type="stmt"/>
|
|
190
|
+
<line num="353" count="0" type="stmt"/>
|
|
191
|
+
<line num="354" count="0" type="stmt"/>
|
|
192
|
+
<line num="355" count="0" type="stmt"/>
|
|
193
|
+
<line num="358" count="0" type="stmt"/>
|
|
194
|
+
<line num="360" count="0" type="cond" truecount="0" falsecount="2"/>
|
|
195
|
+
<line num="361" count="0" type="stmt"/>
|
|
196
|
+
<line num="362" count="0" type="cond" truecount="0" falsecount="2"/>
|
|
197
|
+
<line num="363" count="0" type="stmt"/>
|
|
198
|
+
<line num="364" count="0" type="stmt"/>
|
|
199
|
+
<line num="365" count="0" type="stmt"/>
|
|
200
|
+
<line num="366" count="0" type="stmt"/>
|
|
201
|
+
<line num="370" count="0" type="stmt"/>
|
|
202
|
+
<line num="375" count="0" type="stmt"/>
|
|
203
|
+
<line num="376" count="0" type="cond" truecount="0" falsecount="2"/>
|
|
204
|
+
<line num="377" count="0" type="stmt"/>
|
|
205
|
+
<line num="378" count="0" type="stmt"/>
|
|
206
|
+
<line num="381" count="0" type="stmt"/>
|
|
207
|
+
<line num="382" count="0" type="stmt"/>
|
|
208
|
+
<line num="383" count="0" type="stmt"/>
|
|
209
|
+
<line num="384" count="0" type="stmt"/>
|
|
210
|
+
<line num="386" count="0" type="stmt"/>
|
|
211
|
+
<line num="390" count="1" type="cond" truecount="1" falsecount="1"/>
|
|
212
|
+
<line num="391" count="0" type="stmt"/>
|
|
213
|
+
<line num="392" count="0" type="stmt"/>
|
|
214
|
+
<line num="394" count="0" type="stmt"/>
|
|
215
|
+
<line num="395" count="0" type="stmt"/>
|
|
216
|
+
<line num="400" count="1" type="stmt"/>
|
|
217
|
+
</file>
|
|
5
218
|
</project>
|
|
6
219
|
</coverage>
|