@scenarist/core 0.3.0 → 0.3.1

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.
@@ -52,6 +52,10 @@ export declare const LogEvents: {
52
52
  readonly STATE_CAPTURED: "state_captured";
53
53
  /** State injected into response */
54
54
  readonly STATE_INJECTED: "state_injected";
55
+ /** State set via afterResponse.setState */
56
+ readonly STATE_SET: "state_set";
57
+ /** State response resolved (condition matched or default) */
58
+ readonly STATE_RESPONSE_RESOLVED: "state_response_resolved";
55
59
  /** Sequence advanced to next response */
56
60
  readonly SEQUENCE_ADVANCED: "sequence_advanced";
57
61
  /** Sequence exhausted all responses */
@@ -1 +1 @@
1
- {"version":3,"file":"log-events.d.ts","sourceRoot":"","sources":["../../src/domain/log-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa;IACxB,oEAAoE;;IAEpE,yCAAyC;;IAEzC,yCAAyC;;IAEzC,kCAAkC;;IAElC,8BAA8B;;CAEtB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,SAAS;IAEpB,uCAAuC;;IAEvC,mDAAmD;;IAEnD,mCAAmC;;IAEnC,kCAAkC;;IAIlC,2CAA2C;;IAE3C,4CAA4C;;IAE5C,sCAAsC;;IAEtC,kCAAkC;;IAIlC,mCAAmC;;IAEnC,mCAAmC;;IAInC,yCAAyC;;IAEzC,uCAAuC;;IAIvC,yCAAyC;;IAEzC,8CAA8C;;IAE9C,qCAAqC;;CAE7B,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC"}
1
+ {"version":3,"file":"log-events.d.ts","sourceRoot":"","sources":["../../src/domain/log-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa;IACxB,oEAAoE;;IAEpE,yCAAyC;;IAEzC,yCAAyC;;IAEzC,kCAAkC;;IAElC,8BAA8B;;CAEtB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,SAAS;IAEpB,uCAAuC;;IAEvC,mDAAmD;;IAEnD,mCAAmC;;IAEnC,kCAAkC;;IAIlC,2CAA2C;;IAE3C,4CAA4C;;IAE5C,sCAAsC;;IAEtC,kCAAkC;;IAIlC,mCAAmC;;IAEnC,mCAAmC;;IAEnC,2CAA2C;;IAE3C,6DAA6D;;IAI7D,yCAAyC;;IAEzC,uCAAuC;;IAIvC,yCAAyC;;IAEzC,8CAA8C;;IAE9C,qCAAqC;;CAE7B,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC"}
@@ -55,6 +55,10 @@ export const LogEvents = {
55
55
  STATE_CAPTURED: "state_captured",
56
56
  /** State injected into response */
57
57
  STATE_INJECTED: "state_injected",
58
+ /** State set via afterResponse.setState */
59
+ STATE_SET: "state_set",
60
+ /** State response resolved (condition matched or default) */
61
+ STATE_RESPONSE_RESOLVED: "state_response_resolved",
58
62
  // Sequence progression
59
63
  /** Sequence advanced to next response */
60
64
  SEQUENCE_ADVANCED: "sequence_advanced",
@@ -1 +1 @@
1
- {"version":3,"file":"response-selector.d.ts","sourceRoot":"","sources":["../../src/domain/response-selector.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,MAAM,EACP,MAAM,mBAAmB,CAAC;AAiB3B;;GAEG;AACH,KAAK,6BAA6B,GAAG;IACnC,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GACjC,UAAS,6BAAkC,KAC1C,gBAgQF,CAAC"}
1
+ {"version":3,"file":"response-selector.d.ts","sourceRoot":"","sources":["../../src/domain/response-selector.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,MAAM,EACP,MAAM,mBAAmB,CAAC;AAiB3B;;GAEG;AACH,KAAK,6BAA6B,GAAG;IACnC,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GACjC,UAAS,6BAAkC,KAC1C,gBAuQF,CAAC"}
@@ -72,11 +72,14 @@ export const createResponseSelector = (options = {}) => {
72
72
  continue;
73
73
  }
74
74
  // No match criteria = fallback mock (always matches)
75
- // Log fallback evaluation
75
+ // Log fallback evaluation with response type info for debugging Issue #328
76
76
  logger.debug(LogCategories.MATCHING, LogEvents.MOCK_MATCH_EVALUATED, logContext, {
77
77
  mockIndex,
78
78
  matched: true,
79
79
  hasCriteria: false,
80
+ hasSequence: !!mock.sequence,
81
+ hasStateResponse: !!mock.stateResponse,
82
+ hasResponse: !!mock.response,
80
83
  });
81
84
  // Dynamic response types (sequence, stateResponse) get higher priority than simple responses
82
85
  // This ensures they are selected over simple fallback responses
@@ -105,7 +108,7 @@ export const createResponseSelector = (options = {}) => {
105
108
  specificity,
106
109
  });
107
110
  // Select response (single, sequence, or stateResponse)
108
- const response = selectResponseFromMock(testId, scenarioId, mockIndex, mock, sequenceTracker, stateManager);
111
+ const response = selectResponseFromMock(testId, scenarioId, mockIndex, mock, sequenceTracker, stateManager, logger);
109
112
  if (!response) {
110
113
  return {
111
114
  success: false,
@@ -141,6 +144,9 @@ export const createResponseSelector = (options = {}) => {
141
144
  // Apply afterResponse.setState to mutate state for subsequent requests
142
145
  if (mock.afterResponse?.setState && stateManager) {
143
146
  stateManager.merge(testId, mock.afterResponse.setState);
147
+ logger.debug(LogCategories.STATE, LogEvents.STATE_SET, logContext, {
148
+ setState: mock.afterResponse.setState,
149
+ });
144
150
  }
145
151
  return { success: true, data: finalResponse };
146
152
  }
@@ -199,9 +205,11 @@ export const createResponseSelector = (options = {}) => {
199
205
  * @param mock - The mock definition
200
206
  * @param sequenceTracker - Optional sequence tracker for Phase 2
201
207
  * @param stateManager - Optional state manager for stateResponse
208
+ * @param logger - Logger for debugging
202
209
  * @returns ScenaristResponse or null if mock has no response type
203
210
  */
204
- const selectResponseFromMock = (testId, scenarioId, mockIndex, mock, sequenceTracker, stateManager) => {
211
+ const selectResponseFromMock = (testId, scenarioId, mockIndex, mock, sequenceTracker, stateManager, logger) => {
212
+ const logContext = { testId, scenarioId };
205
213
  // Phase 2: If mock has a sequence, use sequence tracker
206
214
  if (mock.sequence) {
207
215
  if (!sequenceTracker) {
@@ -222,7 +230,7 @@ const selectResponseFromMock = (testId, scenarioId, mockIndex, mock, sequenceTra
222
230
  }
223
231
  // State-aware response: evaluate conditions against current state
224
232
  if (mock.stateResponse) {
225
- return resolveStateResponse(testId, mock.stateResponse, stateManager);
233
+ return resolveStateResponse(testId, mock.stateResponse, stateManager, logger, logContext);
226
234
  }
227
235
  // Phase 1: Single response
228
236
  if (mock.response) {
@@ -240,18 +248,36 @@ const selectResponseFromMock = (testId, scenarioId, mockIndex, mock, sequenceTra
240
248
  * @param testId - Test ID for state isolation
241
249
  * @param stateResponse - The stateResponse configuration
242
250
  * @param stateManager - Optional state manager for state lookup
251
+ * @param logger - Logger for debugging
252
+ * @param logContext - Context for log messages
243
253
  * @returns The resolved response (matching condition or default)
244
254
  */
245
- const resolveStateResponse = (testId, stateResponse, stateManager) => {
255
+ const resolveStateResponse = (testId, stateResponse, stateManager, logger, logContext) => {
246
256
  // Without stateManager, always return default
247
257
  if (!stateManager) {
258
+ logger.debug(LogCategories.STATE, LogEvents.STATE_RESPONSE_RESOLVED, logContext, {
259
+ result: "default",
260
+ reason: "no_state_manager",
261
+ });
248
262
  return stateResponse.default;
249
263
  }
250
264
  // Get current state for this test
251
265
  const currentState = stateManager.getAll(testId);
252
266
  // Create resolver and evaluate conditions
253
267
  const resolver = createStateResponseResolver();
254
- return resolver.resolveResponse(stateResponse, currentState);
268
+ const response = resolver.resolveResponse(stateResponse, currentState);
269
+ // Log which response was selected and why
270
+ const isDefault = response === stateResponse.default;
271
+ const matchedCondition = isDefault
272
+ ? null
273
+ : stateResponse.conditions.find((c) => resolver.resolveResponse({ default: stateResponse.default, conditions: [c] }, currentState) !== stateResponse.default);
274
+ logger.debug(LogCategories.STATE, LogEvents.STATE_RESPONSE_RESOLVED, logContext, {
275
+ result: isDefault ? "default" : "condition",
276
+ currentState,
277
+ conditionsCount: stateResponse.conditions.length,
278
+ matchedWhen: matchedCondition?.when ?? null,
279
+ });
280
+ return response;
255
281
  };
256
282
  /**
257
283
  * Calculate specificity score for match criteria.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scenarist/core",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Internal: Hexagonal architecture core for scenario-based testing with MSW",
5
5
  "author": "Paul Hammond (citypaul) <paul@packsoftware.co.uk>",
6
6
  "license": "MIT",