@schmock/angular 1.0.4 → 1.1.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.
package/dist/index.d.ts CHANGED
@@ -53,4 +53,66 @@ export declare function provideSchmockInterceptor(mock: CallableMockInstance, op
53
53
  useClass: new () => HttpInterceptor;
54
54
  multi: boolean;
55
55
  };
56
+ /**
57
+ * Helper to create a 404 Not Found response
58
+ * @example mock('GET /api/users/999', notFound('User not found'))
59
+ */
60
+ export declare function notFound(message?: string | object): [number, object];
61
+ /**
62
+ * Helper to create a 400 Bad Request response
63
+ * @example mock('POST /api/users', badRequest('Invalid email format'))
64
+ */
65
+ export declare function badRequest(message?: string | object): [number, object];
66
+ /**
67
+ * Helper to create a 401 Unauthorized response
68
+ * @example mock('GET /api/protected', unauthorized('Token expired'))
69
+ */
70
+ export declare function unauthorized(message?: string | object): [number, object];
71
+ /**
72
+ * Helper to create a 403 Forbidden response
73
+ * @example mock('GET /api/admin', forbidden('Admin access required'))
74
+ */
75
+ export declare function forbidden(message?: string | object): [number, object];
76
+ /**
77
+ * Helper to create a 500 Internal Server Error response
78
+ * @example mock('GET /api/broken', serverError('Database connection failed'))
79
+ */
80
+ export declare function serverError(message?: string | object): [number, object];
81
+ /**
82
+ * Helper to create a 201 Created response
83
+ * @example mock('POST /api/users', created({ id: 1, name: 'John' }))
84
+ */
85
+ export declare function created(body: object): [number, object];
86
+ /**
87
+ * Helper to create a 204 No Content response
88
+ * @example mock('DELETE /api/users/1', noContent())
89
+ */
90
+ export declare function noContent(): [number, null];
91
+ /**
92
+ * Pagination options
93
+ */
94
+ export interface PaginateOptions {
95
+ page?: number;
96
+ pageSize?: number;
97
+ }
98
+ /**
99
+ * Paginated response structure
100
+ */
101
+ export interface PaginatedResponse<T> {
102
+ data: T[];
103
+ page: number;
104
+ pageSize: number;
105
+ total: number;
106
+ totalPages: number;
107
+ }
108
+ /**
109
+ * Helper to create a paginated response
110
+ * @example
111
+ * const items = [{ id: 1 }, { id: 2 }, { id: 3 }]
112
+ * mock('GET /api/items', ({ query }) => paginate(items, {
113
+ * page: parseInt(query.page || '1'),
114
+ * pageSize: parseInt(query.pageSize || '10')
115
+ * }))
116
+ */
117
+ export declare function paginate<T>(items: T[], options?: PaginateOptions): PaginatedResponse<T>;
56
118
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,eAAe,EACf,WAAW,EACZ,MAAM,sBAAsB,CAAC;AAO9B,OAAO,KAAK,EACV,oBAAoB,EAEpB,cAAc,EACf,MAAM,eAAe,CAAC;AAwBvB;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC;IAElE;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,KAAK;QAChD,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAChC,CAAC;IAEF;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAClB,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,KACtB,cAAc,CAAC;CACrB;AA2CD;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,oBAAoB,EAC1B,OAAO,GAAE,qBAA0B,GAClC,UAAU,eAAe,CAsH3B;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,oBAAoB,EAC1B,OAAO,CAAC,EAAE,qBAAqB;;wBA7HpB,eAAe;;EAoI3B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,eAAe,EACf,WAAW,EACZ,MAAM,sBAAsB,CAAC;AAO9B,OAAO,KAAK,EACV,oBAAoB,EAEpB,cAAc,EACf,MAAM,eAAe,CAAC;AAyCvB;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC;IAElE;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,KAAK;QAChD,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAChC,CAAC;IAEF;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAClB,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,KACtB,cAAc,CAAC;CACrB;AA8ED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,oBAAoB,EAC1B,OAAO,GAAE,qBAA0B,GAClC,UAAU,eAAe,CAuI3B;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,oBAAoB,EAC1B,OAAO,CAAC,EAAE,qBAAqB;;wBA9IpB,eAAe;;EAqJ3B;AAMD;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,OAAO,GAAE,MAAM,GAAG,MAAoB,GACrC,CAAC,MAAM,EAAE,MAAM,CAAC,CAGlB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,OAAO,GAAE,MAAM,GAAG,MAAsB,GACvC,CAAC,MAAM,EAAE,MAAM,CAAC,CAGlB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,GAAE,MAAM,GAAG,MAAuB,GACxC,CAAC,MAAM,EAAE,MAAM,CAAC,CAGlB;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,OAAO,GAAE,MAAM,GAAG,MAAoB,GACrC,CAAC,MAAM,EAAE,MAAM,CAAC,CAGlB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,OAAO,GAAE,MAAM,GAAG,MAAgC,GACjD,CAAC,MAAM,EAAE,MAAM,CAAC,CAGlB;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAEtD;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAE1C;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,KAAK,EAAE,CAAC,EAAE,EACV,OAAO,GAAE,eAAoB,GAC5B,iBAAiB,CAAC,CAAC,CAAC,CAgBtB"}
package/dist/index.js CHANGED
@@ -35,20 +35,52 @@ function toHttpMethod(method) {
35
35
  }
36
36
  return "GET";
37
37
  }
38
- function extractQueryParams(url) {
39
- const queryStart = url.indexOf("?");
40
- if (queryStart === -1)
41
- return {};
42
- const params = new URLSearchParams(url.slice(queryStart + 1));
38
+ function getStatusText(status) {
39
+ const statusTexts = {
40
+ 200: "OK",
41
+ 201: "Created",
42
+ 204: "No Content",
43
+ 400: "Bad Request",
44
+ 401: "Unauthorized",
45
+ 403: "Forbidden",
46
+ 404: "Not Found",
47
+ 500: "Internal Server Error"
48
+ };
49
+ return statusTexts[status] || "Unknown";
50
+ }
51
+ function extractQueryParams(request) {
43
52
  const result = {};
44
- params.forEach((value, key) => {
45
- result[key] = value;
53
+ request.params.keys().forEach((key) => {
54
+ const value = request.params.get(key);
55
+ if (value !== null) {
56
+ result[key] = value;
57
+ }
46
58
  });
59
+ const url = request.url;
60
+ const queryStart = url.indexOf("?");
61
+ if (queryStart !== -1) {
62
+ const urlParams = new URLSearchParams(url.slice(queryStart + 1));
63
+ urlParams.forEach((value, key) => {
64
+ if (!(key in result)) {
65
+ result[key] = value;
66
+ }
67
+ });
68
+ }
47
69
  return result;
48
70
  }
49
- function extractPath(url) {
71
+ function extractPathname(url) {
50
72
  const queryStart = url.indexOf("?");
51
- return queryStart === -1 ? url : url.slice(0, queryStart);
73
+ const urlWithoutQuery = queryStart === -1 ? url : url.slice(0, queryStart);
74
+ if (urlWithoutQuery.includes("://")) {
75
+ try {
76
+ const parsed = new URL(urlWithoutQuery);
77
+ return parsed.pathname;
78
+ } catch {}
79
+ }
80
+ if (!urlWithoutQuery.startsWith("/")) {
81
+ return `/${urlWithoutQuery}`;
82
+ }
83
+ return urlWithoutQuery;
52
84
  }
53
85
  function headersToObject(request) {
54
86
  const headers = {};
@@ -71,11 +103,11 @@ function createSchmockInterceptor(mock, options = {}) {
71
103
 
72
104
  class SchmockInterceptor {
73
105
  intercept(req, next) {
74
- if (baseUrl && !req.url.startsWith(baseUrl)) {
106
+ const path = extractPathname(req.url);
107
+ if (baseUrl && !path.startsWith(baseUrl)) {
75
108
  return next.handle(req);
76
109
  }
77
- const path = extractPath(req.url);
78
- const query = extractQueryParams(req.url);
110
+ const query = extractQueryParams(req);
79
111
  let requestData = {
80
112
  method: toHttpMethod(req.method),
81
113
  path,
@@ -111,15 +143,26 @@ function createSchmockInterceptor(mock, options = {}) {
111
143
  if (transformResponse) {
112
144
  response = transformResponse(response, req);
113
145
  }
114
- const httpResponse = new HttpResponse({
115
- body: response.body,
116
- status: response.status || 200,
117
- statusText: "OK",
118
- url: req.url,
119
- headers: new HttpHeaders(response.headers || {})
120
- });
121
- observer.next(httpResponse);
122
- observer.complete();
146
+ const status = response.status || 200;
147
+ if (status >= 400) {
148
+ observer.error(new HttpErrorResponse({
149
+ error: response.body,
150
+ status,
151
+ statusText: getStatusText(status),
152
+ url: req.url,
153
+ headers: new HttpHeaders(response.headers || {})
154
+ }));
155
+ } else {
156
+ const httpResponse = new HttpResponse({
157
+ body: response.body,
158
+ status,
159
+ statusText: getStatusText(status),
160
+ url: req.url,
161
+ headers: new HttpHeaders(response.headers || {})
162
+ });
163
+ observer.next(httpResponse);
164
+ observer.complete();
165
+ }
123
166
  }
124
167
  }).catch((error) => {
125
168
  let errorBody;
@@ -154,7 +197,57 @@ function provideSchmockInterceptor(mock, options) {
154
197
  multi: true
155
198
  };
156
199
  }
200
+ function notFound(message = "Not Found") {
201
+ const body = typeof message === "string" ? { message } : message;
202
+ return [404, body];
203
+ }
204
+ function badRequest(message = "Bad Request") {
205
+ const body = typeof message === "string" ? { message } : message;
206
+ return [400, body];
207
+ }
208
+ function unauthorized(message = "Unauthorized") {
209
+ const body = typeof message === "string" ? { message } : message;
210
+ return [401, body];
211
+ }
212
+ function forbidden(message = "Forbidden") {
213
+ const body = typeof message === "string" ? { message } : message;
214
+ return [403, body];
215
+ }
216
+ function serverError(message = "Internal Server Error") {
217
+ const body = typeof message === "string" ? { message } : message;
218
+ return [500, body];
219
+ }
220
+ function created(body) {
221
+ return [201, body];
222
+ }
223
+ function noContent() {
224
+ return [204, null];
225
+ }
226
+ function paginate(items, options = {}) {
227
+ const page = options.page || 1;
228
+ const pageSize = options.pageSize || 10;
229
+ const total = items.length;
230
+ const totalPages = Math.ceil(total / pageSize);
231
+ const start = (page - 1) * pageSize;
232
+ const end = start + pageSize;
233
+ const data = items.slice(start, end);
234
+ return {
235
+ data,
236
+ page,
237
+ pageSize,
238
+ total,
239
+ totalPages
240
+ };
241
+ }
157
242
  export {
243
+ unauthorized,
244
+ serverError,
158
245
  provideSchmockInterceptor,
159
- createSchmockInterceptor
246
+ paginate,
247
+ notFound,
248
+ noContent,
249
+ forbidden,
250
+ created,
251
+ createSchmockInterceptor,
252
+ badRequest
160
253
  };
package/package.json CHANGED
@@ -1,10 +1,16 @@
1
1
  {
2
2
  "name": "@schmock/angular",
3
- "version": "1.0.4",
3
+ "version": "1.1.1",
4
4
  "description": "Angular HTTP interceptor adapter for Schmock",
5
+ "type": "module",
5
6
  "main": "dist/index.js",
6
7
  "types": "dist/index.d.ts",
7
- "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
8
14
  "files": [
9
15
  "dist"
10
16
  ],
@@ -16,8 +22,10 @@
16
22
  "build:types": "rm -f tsconfig.tsbuildinfo && tsc --build",
17
23
  "test": "vitest run",
18
24
  "test:watch": "vitest",
25
+ "test:bdd": "vitest run --config vitest.config.bdd.ts",
19
26
  "lint": "biome check src",
20
- "lint:fix": "biome check --write src"
27
+ "lint:fix": "biome check --write src",
28
+ "check:publish": "publint && attw --pack --ignore-rules cjs-resolves-to-esm"
21
29
  },
22
30
  "peerDependencies": {
23
31
  "@angular/common": ">=15.0.0",
@@ -26,6 +34,7 @@
26
34
  "rxjs": "^7.0.0"
27
35
  },
28
36
  "devDependencies": {
37
+ "@amiceli/vitest-cucumber": "^6.1.0",
29
38
  "@angular/common": "^21.0.3",
30
39
  "@angular/compiler": "^20.3.9",
31
40
  "@angular/core": "^21.0.3",