@scenarist/msw-adapter 0.3.2 → 0.3.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-handler.d.ts","sourceRoot":"","sources":["../../src/handlers/dynamic-handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AACvC,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EAIjB,gBAAgB,EAChB,cAAc,EACd,MAAM,EACP,MAAM,iBAAiB,CAAC;AAKzB,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACjD,QAAQ,CAAC,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,cAAc,GAAG,SAAS,CAAC;IAC3E,QAAQ,CAAC,qBAAqB,EAAE,CAC9B,UAAU,EAAE,MAAM,KACf,iBAAiB,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAqGF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,qBAAqB,KAC7B,WAiIF,CAAC"}
1
+ {"version":3,"file":"dynamic-handler.d.ts","sourceRoot":"","sources":["../../src/handlers/dynamic-handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AACvC,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EAIjB,gBAAgB,EAChB,cAAc,EACd,MAAM,EACP,MAAM,iBAAiB,CAAC;AAKzB,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACjD,QAAQ,CAAC,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,cAAc,GAAG,SAAS,CAAC;IAC3E,QAAQ,CAAC,qBAAqB,EAAE,CAC9B,UAAU,EAAE,MAAM,KACf,iBAAiB,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAoIF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,qBAAqB,KAC7B,WAiIF,CAAC"}
@@ -44,41 +44,65 @@ const extractHttpRequestContext = async (request) => {
44
44
  query,
45
45
  };
46
46
  };
47
+ /**
48
+ * Check if a mock matches the request's method and URL.
49
+ * Returns match result with extracted URL params if matching.
50
+ */
51
+ const mockMatchesRequest = (mock, method, url) => {
52
+ const methodMatches = mock.method.toUpperCase() === method.toUpperCase();
53
+ if (!methodMatches) {
54
+ return { matches: false, params: {} };
55
+ }
56
+ const urlMatch = matchesUrl(mock.url, url);
57
+ return { matches: urlMatch.matches, params: urlMatch.params ?? {} };
58
+ };
47
59
  /**
48
60
  * Get mocks from active scenario, with default scenario mocks as fallback.
49
61
  * Returns URL-matching mocks with their extracted params for ResponseSelector to evaluate.
50
62
  *
51
- * Default mocks are ALWAYS included (if they match URL+method).
52
- * Active scenario mocks are added after defaults, allowing them to override
53
- * based on specificity (mocks with match criteria have higher specificity).
63
+ * Mock selection priority (Issue #335):
64
+ * 1. If no active scenario use default scenario mocks
65
+ * 2. If active scenario has a fallback mock (no match criteria) use ONLY active mocks
66
+ * 3. If active scenario has only conditional mocks → include default as backup
67
+ *
68
+ * A "fallback mock" is one without match criteria - it always matches if URL+method match.
69
+ * When active scenario explicitly covers an endpoint with a fallback mock, we don't
70
+ * include default's mock for that endpoint, preventing specificity-based conflicts.
54
71
  *
55
72
  * Each mock is paired with params extracted from its URL pattern.
56
73
  * After ResponseSelector chooses a mock, we use THAT mock's params.
57
74
  */
58
75
  const getMocksFromScenarios = (activeScenario, getScenarioDefinition, method, url) => {
59
76
  const mocksWithParams = [];
60
- // Step 1: ALWAYS include default scenario mocks first
61
- // These act as fallback when active scenario mocks don't match
62
- const defaultScenario = getScenarioDefinition("default");
63
- if (defaultScenario) {
64
- defaultScenario.mocks.forEach((mock) => {
65
- const methodMatches = mock.method.toUpperCase() === method.toUpperCase();
66
- const urlMatch = matchesUrl(mock.url, url);
67
- if (methodMatches && urlMatch.matches) {
68
- mocksWithParams.push({ mock, params: urlMatch.params });
69
- }
70
- });
71
- }
72
- // Step 2: Add active scenario mocks (if any)
73
- // These override defaults based on specificity (via ResponseSelector)
77
+ // Step 1: Check active scenario first
78
+ // Track if active has a fallback mock (no match criteria) for this URL+method
79
+ let activeHasFallbackMock = false;
74
80
  if (activeScenario) {
75
81
  const scenarioDefinition = getScenarioDefinition(activeScenario.scenarioId);
76
82
  if (scenarioDefinition) {
77
83
  scenarioDefinition.mocks.forEach((mock) => {
78
- const methodMatches = mock.method.toUpperCase() === method.toUpperCase();
79
- const urlMatch = matchesUrl(mock.url, url);
80
- if (methodMatches && urlMatch.matches) {
81
- mocksWithParams.push({ mock, params: urlMatch.params });
84
+ const match = mockMatchesRequest(mock, method, url);
85
+ if (match.matches) {
86
+ mocksWithParams.push({ mock, params: match.params });
87
+ // A mock without match criteria is a "fallback" - it always matches
88
+ if (!mock.match) {
89
+ activeHasFallbackMock = true;
90
+ }
91
+ }
92
+ });
93
+ }
94
+ }
95
+ // Step 2: Include default scenario mocks only if:
96
+ // - No active scenario is set, OR
97
+ // - Active scenario doesn't have a fallback mock for this URL+method
98
+ // (i.e., active only has conditional mocks, so default is needed as backup)
99
+ if (!activeScenario || !activeHasFallbackMock) {
100
+ const defaultScenario = getScenarioDefinition("default");
101
+ if (defaultScenario) {
102
+ defaultScenario.mocks.forEach((mock) => {
103
+ const match = mockMatchesRequest(mock, method, url);
104
+ if (match.matches) {
105
+ mocksWithParams.push({ mock, params: match.params });
82
106
  }
83
107
  });
84
108
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scenarist/msw-adapter",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Internal: MSW integration layer for Scenarist framework adapters",
5
5
  "author": "Paul Hammond (citypaul) <paul@packsoftware.co.uk>",
6
6
  "license": "MIT",
@@ -42,7 +42,7 @@
42
42
  ],
43
43
  "dependencies": {
44
44
  "path-to-regexp": "^6.3.0",
45
- "@scenarist/core": "0.3.2"
45
+ "@scenarist/core": "0.3.3"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "msw": "^2.0.0"