@superlikers/microsites-api 0.1.0
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/.npmignore +3 -0
- package/CHANGELOG.md +14 -0
- package/README.md +222 -0
- package/fesm2022/superlikers-microsites-api-forms.mjs +48 -0
- package/fesm2022/superlikers-microsites-api-forms.mjs.map +1 -0
- package/fesm2022/superlikers-microsites-api-testing.mjs +47 -0
- package/fesm2022/superlikers-microsites-api-testing.mjs.map +1 -0
- package/fesm2022/superlikers-microsites-api.mjs +723 -0
- package/fesm2022/superlikers-microsites-api.mjs.map +1 -0
- package/package.json +56 -0
- package/types/superlikers-microsites-api-forms.d.ts +28 -0
- package/types/superlikers-microsites-api-testing.d.ts +39 -0
- package/types/superlikers-microsites-api.d.ts +1958 -0
package/.npmignore
ADDED
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# @superlikers/microsites-api
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- First release of `@superlikers/microsites-api`, typed Angular 22 services for the Superlikers microsites backend.
|
|
8
|
+
|
|
9
|
+
- `provideMicrositesApi({ baseUrl, onUnauthorized })` configures the library.
|
|
10
|
+
- Services for every domain: Session, Participant, Registrations, Password, Achievements, Activities, Badges, Blogs, Boards, Comments, Entries, External forms, Goals, Metrics, Prizes, Ranking, Referrals, Teams and Votes.
|
|
11
|
+
- Every failure is an `ApiError` (`status`, `code`, `message`, `fieldErrors`), including answers with HTTP 200 and `state: 'error'` and non-JSON answers from disabled modules (`isInvalidResponse`).
|
|
12
|
+
- Models checked against real responses; base models (`BaseParticipant`, `BaseGoal`, `BaseEntry`…) to extend with campaign fields.
|
|
13
|
+
- `@superlikers/microsites-api/testing`: `provideMicrositesApiTesting()` and `createApiError()`.
|
|
14
|
+
- `@superlikers/microsites-api/forms`: `channelValidator()` (requires `@angular/forms`).
|
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# @superlikers/microsites-api
|
|
2
|
+
|
|
3
|
+
Typed Angular services for the Superlikers microsites backend (session, participant, entries, prizes, goals, ranking…).
|
|
4
|
+
|
|
5
|
+
> **Pre-1.0:** the API may still change between minor versions (`0.1` → `0.2`). Pin a minor range (`~0.1.0`) and check the [changelog](./CHANGELOG.md) before upgrading.
|
|
6
|
+
|
|
7
|
+
## Compatibility
|
|
8
|
+
|
|
9
|
+
| `@superlikers/microsites-api` | Angular | RxJS |
|
|
10
|
+
| ----------------------------- | ------- | ------ |
|
|
11
|
+
| `0.x` | `^22.0` | `^7.8` |
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @superlikers/microsites-api
|
|
17
|
+
# or: npm install @superlikers/microsites-api
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
Register the library once in `app.config.ts`:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { ApplicationConfig, inject } from '@angular/core'
|
|
26
|
+
import { Router } from '@angular/router'
|
|
27
|
+
import { provideMicrositesApi } from '@superlikers/microsites-api'
|
|
28
|
+
|
|
29
|
+
import { environment } from '../environments/environment'
|
|
30
|
+
|
|
31
|
+
export const appConfig: ApplicationConfig = {
|
|
32
|
+
providers: [
|
|
33
|
+
provideMicrositesApi({
|
|
34
|
+
baseUrl: environment.baseUrl, // e.g. https://4x.superlikerslabs.com
|
|
35
|
+
onUnauthorized: () => inject(Router).navigate(['/login']) // optional
|
|
36
|
+
})
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
| Option | Required | Description |
|
|
42
|
+
| ---------------- | -------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
43
|
+
| `baseUrl` | yes | Absolute `http(s)` URL of the microsite backend. A trailing slash is removed. An invalid value throws on startup. |
|
|
44
|
+
| `onUnauthorized` | no | Called on every `401` response, in an injection context (`inject()` works). The error is still thrown to the caller. |
|
|
45
|
+
|
|
46
|
+
`HttpClient` needs no extra setup. Every request is sent with `withCredentials: true` (session cookie) and `Accept: application/json`.
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
Inject a service and subscribe (or convert to a signal / promise). Every method returns a cold `Observable`, so nothing is sent until you subscribe.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { Component, inject, signal } from '@angular/core'
|
|
54
|
+
import { isApiError, SessionService } from '@superlikers/microsites-api'
|
|
55
|
+
|
|
56
|
+
@Component({ selector: 'app-login', templateUrl: './login.html' })
|
|
57
|
+
export class Login {
|
|
58
|
+
readonly #session = inject(SessionService)
|
|
59
|
+
protected readonly error = signal('')
|
|
60
|
+
|
|
61
|
+
protected login(email: string, password: string) {
|
|
62
|
+
this.#session.login({ email, password }).subscribe({
|
|
63
|
+
next: () => this.error.set(''),
|
|
64
|
+
error: (error: unknown) => this.error.set(isApiError(error) ? error.message : 'Unexpected error')
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Services
|
|
71
|
+
|
|
72
|
+
| Service | Methods |
|
|
73
|
+
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
74
|
+
| `SessionService` | `getLoginForm`, `login`, `logout`, `getSsoLoginUrl`, `checkLoginRequirements` |
|
|
75
|
+
| `RegistrationsService` | `getSignupForm`, `signup`, `updateParticipant`, `sendEmailVerificationToken`, `validateEmailToken`, `confirmEmail` |
|
|
76
|
+
| `PasswordService` | `changePassword`, `validateChannel`, `sendResetToken`, `resetPassword` |
|
|
77
|
+
| `ParticipantService` | `getCurrent`, `getRank`, `list`, `getByUid`, `savePushSubscription`, `removePushSubscriptions` |
|
|
78
|
+
| `EntriesService` | `listExternals`, `listRedemptions`, `listPhotos`, `listDocuments`, `listPurchases`, `list`, `search`, `createExternal` |
|
|
79
|
+
| `ExternalFormsService` | `listForms`, `getFormFields`, `submit`, `listSubmissions`, `getSubmission`, `updateSubmission` |
|
|
80
|
+
| `ActivitiesService` | `uploadPhoto`, `uploadDocument` |
|
|
81
|
+
| `PrizesService` | `list`, `checkRedeem`, `redeem`, `getWishlist`, `toggleWishlist`, `getExternalCouponData` |
|
|
82
|
+
| `GoalsService` | `listParticipantGoals`, `list`, `accept`, `decline` |
|
|
83
|
+
| `AchievementsService` | `list` |
|
|
84
|
+
| `BadgesService` | `list`, `get`, `getStats` |
|
|
85
|
+
| `RankingService` | `getSegment` |
|
|
86
|
+
| `MetricsService` | `list`, `calculate` |
|
|
87
|
+
| `BoardsService` | `list`, `listReports`, `executeReport` |
|
|
88
|
+
| `BlogsService` | `list`, `get`, `create` |
|
|
89
|
+
| `CommentsService` | `list`, `create` |
|
|
90
|
+
| `VotesService` | `get`, `create`, `update`, `delete` |
|
|
91
|
+
| `TeamsService` | `list`, `get`, `create`, `removeMember` |
|
|
92
|
+
| `ReferralsService` | `changeCode` |
|
|
93
|
+
|
|
94
|
+
Each method documents its endpoint and parameters in its JSDoc (visible on hover in the editor). A method whose campaign module is disabled fails with an `ApiError` (see [Errors](#errors)).
|
|
95
|
+
|
|
96
|
+
### Campaign-specific fields
|
|
97
|
+
|
|
98
|
+
Models hold the fields every campaign has. Campaigns add their own fields (participant properties, goal data, external action data…), so the services that return them take a type parameter. Extend the `Base*` model and pass **your full interface**:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { BaseCurrentParticipant, ParticipantService } from '@superlikers/microsites-api'
|
|
102
|
+
|
|
103
|
+
interface CurrentParticipant extends BaseCurrentParticipant {
|
|
104
|
+
distributor_code: string
|
|
105
|
+
region: string
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
inject(ParticipantService)
|
|
109
|
+
.getCurrent<CurrentParticipant>()
|
|
110
|
+
.subscribe(({ participation }) => console.log(participation.region))
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
| Type parameter of | Default |
|
|
114
|
+
| ---------------------------------------------------------- | ------------------------- |
|
|
115
|
+
| `ParticipantService.getCurrent` | `BaseCurrentParticipant` |
|
|
116
|
+
| `ParticipantService.list` / `getByUid` | `BaseParticipant` |
|
|
117
|
+
| `ParticipantService.getRank` | `BaseParticipantRankData` |
|
|
118
|
+
| `GoalsService.list` / `listParticipantGoals` (`goal_data`) | `GoalData` |
|
|
119
|
+
| `EntriesService.listExternals` (`data`) | `EntryData` |
|
|
120
|
+
| `ExternalFormsService.listSubmissions` / `getSubmission` | `EntryData` |
|
|
121
|
+
| `BlogsService` / `CommentsService` (embedded participant) | `ActivityParticipant` |
|
|
122
|
+
|
|
123
|
+
### Entries
|
|
124
|
+
|
|
125
|
+
`EntriesService` has one method per common entry type (`listExternals`, `listRedemptions`, `listPhotos`, `listDocuments`, `listPurchases`), each typed with its own model. For other types, or several at once, use `list()` and narrow each item with `isEntryType`:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { EntriesService, isEntryType } from '@superlikers/microsites-api'
|
|
129
|
+
|
|
130
|
+
inject(EntriesService)
|
|
131
|
+
.list({ _type: 'ExtraPoints' })
|
|
132
|
+
.subscribe(({ data }) => {
|
|
133
|
+
for (const entry of data) {
|
|
134
|
+
if (isEntryType(entry, 'ExtraPoints')) console.log(entry.concept)
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Entries of a type the library doesn't model yet are returned as `UnknownEntry`: the common fields are typed and the rest are `unknown`.
|
|
140
|
+
|
|
141
|
+
### Query parameters
|
|
142
|
+
|
|
143
|
+
Parameters are serialized the way the backend expects: `null` and `undefined` are skipped, arrays are sent as `key[]=a&key[]=b`, and objects as `key[sub]=value`, for example `date_filter[start]=…`.
|
|
144
|
+
|
|
145
|
+
## Errors
|
|
146
|
+
|
|
147
|
+
Every failure is thrown as an `ApiError`. This includes errors the backend reports with HTTP `200` and `state: 'error'`, so all errors are handled in the `error` callback.
|
|
148
|
+
|
|
149
|
+
| Property | Description |
|
|
150
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
151
|
+
| `message` | Backend message, or a default one. |
|
|
152
|
+
| `status` | HTTP status. `0` = the request never reached the server. |
|
|
153
|
+
| `code` | Backend error code (`code_error`), or `null`. |
|
|
154
|
+
| `fieldErrors` | Validation errors by field, e.g. `{ email: 'is invalid' }`. Empty object when there are none. |
|
|
155
|
+
| `url` | URL of the failed request. |
|
|
156
|
+
| `isNetworkError` | `status === 0` (offline, CORS, DNS…). |
|
|
157
|
+
| `isUnauthorized` | `status === 401`. |
|
|
158
|
+
| `isInvalidResponse` | The server answered with something that is not JSON, usually because the module is disabled for the campaign. |
|
|
159
|
+
| `cause` | The original `HttpErrorResponse`. |
|
|
160
|
+
|
|
161
|
+
Use `isApiError(error)` to narrow an `unknown` error.
|
|
162
|
+
|
|
163
|
+
## Testing (`@superlikers/microsites-api/testing`)
|
|
164
|
+
|
|
165
|
+
Helpers for your app's unit tests. Import them only from spec files.
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import { HttpTestingController } from '@angular/common/http/testing'
|
|
169
|
+
import { TestBed } from '@angular/core/testing'
|
|
170
|
+
import { SessionService } from '@superlikers/microsites-api'
|
|
171
|
+
import { MICROSITES_API_TEST_BASE_URL, provideMicrositesApiTesting } from '@superlikers/microsites-api/testing'
|
|
172
|
+
|
|
173
|
+
TestBed.configureTestingModule({ providers: [provideMicrositesApiTesting()] })
|
|
174
|
+
const http = TestBed.inject(HttpTestingController)
|
|
175
|
+
|
|
176
|
+
TestBed.inject(SessionService).logout().subscribe()
|
|
177
|
+
http.expectOne(`${MICROSITES_API_TEST_BASE_URL}/sessions/logout`).flush({ state: 'success', message: 'ok' })
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
| Export | Description |
|
|
181
|
+
| ------------------------------ | ---------------------------------------------------------------------------------------------------------- |
|
|
182
|
+
| `provideMicrositesApiTesting` | Library config + `HttpClient` + `HttpTestingController`. Accepts config overrides (e.g. `onUnauthorized`). |
|
|
183
|
+
| `MICROSITES_API_TEST_BASE_URL` | The `baseUrl` used in tests, to match requests. |
|
|
184
|
+
| `createApiError` | Builds an `ApiError` as the backend would, to simulate failures with mocked services. |
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { throwError } from 'rxjs'
|
|
188
|
+
import { createApiError } from '@superlikers/microsites-api/testing'
|
|
189
|
+
|
|
190
|
+
{ provide: SessionService, useValue: { login: () => throwError(() => createApiError({ code: 141, message: 'Wrong password' })) } }
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Forms (`@superlikers/microsites-api/forms`)
|
|
194
|
+
|
|
195
|
+
Helpers for Angular reactive forms. This entry point requires `@angular/forms`, an optional peer dependency that Angular apps usually already have.
|
|
196
|
+
|
|
197
|
+
`channelValidator(channel, options?)` is an async validator that checks, against the backend, that a participant exists for an email or phone number. It is meant for "forgot password" forms. Call it in an injection context, such as a field initializer.
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { channelValidator } from '@superlikers/microsites-api/forms'
|
|
201
|
+
|
|
202
|
+
readonly form = inject(FormBuilder).nonNullable.group({
|
|
203
|
+
email: ['', [Validators.required, Validators.email], [channelValidator('email')]]
|
|
204
|
+
})
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
```html
|
|
208
|
+
@if (form.controls.email.errors?.['channel']; as error) {
|
|
209
|
+
<p>{{ error.message }}</p>
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
It waits 500 ms after the last change before calling the backend (`{ debounceMs }` to change it) and leaves empty values to `Validators.required`.
|
|
214
|
+
|
|
215
|
+
## Versioning
|
|
216
|
+
|
|
217
|
+
The package follows [semver](https://semver.org), independent of Angular's version. While in `0.x`:
|
|
218
|
+
|
|
219
|
+
- `0.MINOR.0`: may contain breaking changes.
|
|
220
|
+
- `0.x.PATCH`: new features and fixes, no breaking changes.
|
|
221
|
+
|
|
222
|
+
Every release is documented in the [changelog](./CHANGELOG.md).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { inject } from '@angular/core';
|
|
2
|
+
import { PasswordService, isApiError } from '@superlikers/microsites-api';
|
|
3
|
+
import { of, timer, switchMap, map, catchError } from 'rxjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Validates that a participant exists for the given channel value (an email or a phone number) against the
|
|
7
|
+
* backend, for "forgot password" forms. Must be called in an injection context (e.g. a component field
|
|
8
|
+
* initializer). Debounces while the control keeps changing; Angular cancels the pending check on every new value.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* readonly form = this.#fb.nonNullable.group({
|
|
13
|
+
* correo: ['', [Validators.required, Validators.email], [channelValidator('email')]]
|
|
14
|
+
* })
|
|
15
|
+
* ```
|
|
16
|
+
* ```html
|
|
17
|
+
* @if (form.controls.correo.errors?.['channel']; as error) {
|
|
18
|
+
* <p>{{ error.message }}</p>
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
function channelValidator(channel, options = {}) {
|
|
23
|
+
const password = inject(PasswordService);
|
|
24
|
+
const debounceMs = options.debounceMs ?? 500;
|
|
25
|
+
return (control) => {
|
|
26
|
+
const value = control.value?.trim();
|
|
27
|
+
if (!value)
|
|
28
|
+
return of(null); // let Validators.required handle an empty value
|
|
29
|
+
return timer(debounceMs).pipe(switchMap(() => password.validateChannel(channel, value)), map(() => null), // errors (including HTTP 200 with state 'error') arrive as ApiError
|
|
30
|
+
catchError((error) => of(channelError(isApiError(error) ? error.message : undefined))));
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function channelError(message) {
|
|
34
|
+
return { channel: { message: message || 'No pudimos validar el dato.' } };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/*
|
|
38
|
+
* Public API Surface of @superlikers/microsites-api/forms
|
|
39
|
+
*
|
|
40
|
+
* Requires @angular/forms. Import only where you build forms with it.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Generated bundle index. Do not edit.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
export { channelValidator };
|
|
48
|
+
//# sourceMappingURL=superlikers-microsites-api-forms.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"superlikers-microsites-api-forms.mjs","sources":["../../../projects/microsites-api/forms/src/channel-validator.ts","../../../projects/microsites-api/forms/src/public-api.ts","../../../projects/microsites-api/forms/src/superlikers-microsites-api-forms.ts"],"sourcesContent":["import { inject } from '@angular/core'\nimport { AbstractControl, AsyncValidatorFn, ValidationErrors } from '@angular/forms'\nimport { isApiError, NotificationChannel, PasswordService } from '@superlikers/microsites-api'\nimport { catchError, map, of, switchMap, timer } from 'rxjs'\n\nexport interface ChannelValidatorOptions {\n /** Debounce before validating against the backend, in ms. @default 500 */\n debounceMs?: number\n}\n\n/**\n * Validates that a participant exists for the given channel value (an email or a phone number) against the\n * backend, for \"forgot password\" forms. Must be called in an injection context (e.g. a component field\n * initializer). Debounces while the control keeps changing; Angular cancels the pending check on every new value.\n *\n * @example\n * ```ts\n * readonly form = this.#fb.nonNullable.group({\n * correo: ['', [Validators.required, Validators.email], [channelValidator('email')]]\n * })\n * ```\n * ```html\n * @if (form.controls.correo.errors?.['channel']; as error) {\n * <p>{{ error.message }}</p>\n * }\n * ```\n */\nexport function channelValidator(channel: NotificationChannel, options: ChannelValidatorOptions = {}): AsyncValidatorFn {\n const password = inject(PasswordService)\n const debounceMs = options.debounceMs ?? 500\n\n return (control: AbstractControl<string | null>) => {\n const value = control.value?.trim()\n if (!value) return of(null) // let Validators.required handle an empty value\n\n return timer(debounceMs).pipe(\n switchMap(() => password.validateChannel(channel, value)),\n map(() => null), // errors (including HTTP 200 with state 'error') arrive as ApiError\n catchError((error: unknown) => of(channelError(isApiError(error) ? error.message : undefined)))\n )\n }\n}\n\nfunction channelError(message?: string): ValidationErrors {\n return { channel: { message: message || 'No pudimos validar el dato.' } }\n}\n","/*\n * Public API Surface of @superlikers/microsites-api/forms\n *\n * Requires @angular/forms. Import only where you build forms with it.\n */\n\nexport { channelValidator } from './channel-validator'\nexport type { ChannelValidatorOptions } from './channel-validator'\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;AAUA;;;;;;;;;;;;;;;;AAgBG;SACa,gBAAgB,CAAC,OAA4B,EAAE,UAAmC,EAAE,EAAA;AAClG,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,eAAe,CAAC;AACxC,IAAA,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,GAAG;IAE5C,OAAO,CAAC,OAAuC,KAAI;QACjD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE;AACnC,QAAA,IAAI,CAAC,KAAK;AAAE,YAAA,OAAO,EAAE,CAAC,IAAI,CAAC,CAAA;AAE3B,QAAA,OAAO,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAC3B,SAAS,CAAC,MAAM,QAAQ,CAAC,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,EACzD,GAAG,CAAC,MAAM,IAAI,CAAC;AACf,QAAA,UAAU,CAAC,CAAC,KAAc,KAAK,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAChG;AACH,IAAA,CAAC;AACH;AAEA,SAAS,YAAY,CAAC,OAAgB,EAAA;IACpC,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,IAAI,6BAA6B,EAAE,EAAE;AAC3E;;AC7CA;;;;AAIG;;ACJH;;AAEG;;"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { HttpErrorResponse, provideHttpClient } from '@angular/common/http';
|
|
2
|
+
import { ApiError, provideMicrositesApi } from '@superlikers/microsites-api';
|
|
3
|
+
import { provideHttpClientTesting } from '@angular/common/http/testing';
|
|
4
|
+
import { makeEnvironmentProviders } from '@angular/core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Builds an {@link ApiError} as if the backend had answered with an error, to simulate failures in tests.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* { provide: SessionService, useValue: { login: () => throwError(() => createApiError({ code: 141, message: 'Contraseña incorrecta' })) } }
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
function createApiError({ status = 404, message, code, fieldErrors, url } = {}) {
|
|
15
|
+
const body = { state: 'error', message, code_error: code, errors: fieldErrors };
|
|
16
|
+
return new ApiError(new HttpErrorResponse({ status, error: body, url }));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** baseUrl used by {@link provideMicrositesApiTesting}; use it to match requests in `HttpTestingController`. */
|
|
20
|
+
const MICROSITES_API_TEST_BASE_URL = 'https://microsite.test';
|
|
21
|
+
/**
|
|
22
|
+
* Everything a test needs to use the library without a real backend:
|
|
23
|
+
* the library config, `HttpClient` and `HttpTestingController`.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* TestBed.configureTestingModule({ providers: [provideMicrositesApiTesting()] })
|
|
28
|
+
* const http = TestBed.inject(HttpTestingController)
|
|
29
|
+
* http.expectOne(`${MICROSITES_API_TEST_BASE_URL}/sessions/logout`).flush({ state: 'success', message: 'ok' })
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
function provideMicrositesApiTesting(config = {}) {
|
|
33
|
+
return makeEnvironmentProviders([provideHttpClient(), provideHttpClientTesting(), provideMicrositesApi({ baseUrl: MICROSITES_API_TEST_BASE_URL, ...config })]);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/*
|
|
37
|
+
* Public API Surface of @superlikers/microsites-api/testing
|
|
38
|
+
*
|
|
39
|
+
* Test helpers for apps that use the library. Import only from spec files.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Generated bundle index. Do not edit.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
export { MICROSITES_API_TEST_BASE_URL, createApiError, provideMicrositesApiTesting };
|
|
47
|
+
//# sourceMappingURL=superlikers-microsites-api-testing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"superlikers-microsites-api-testing.mjs","sources":["../../../projects/microsites-api/testing/src/create-api-error.ts","../../../projects/microsites-api/testing/src/provide-microsites-api-testing.ts","../../../projects/microsites-api/testing/src/public-api.ts","../../../projects/microsites-api/testing/src/superlikers-microsites-api-testing.ts"],"sourcesContent":["import { HttpErrorResponse } from '@angular/common/http'\nimport { ApiError } from '@superlikers/microsites-api'\n\nexport interface CreateApiErrorOptions {\n /** HTTP status. Defaults to `404`, the status the backend uses for most business errors. */\n status?: number\n message?: string\n /** Backend error code (`code_error`). */\n code?: number\n fieldErrors?: Record<string, string>\n url?: string\n}\n\n/**\n * Builds an {@link ApiError} as if the backend had answered with an error, to simulate failures in tests.\n *\n * @example\n * ```ts\n * { provide: SessionService, useValue: { login: () => throwError(() => createApiError({ code: 141, message: 'Contraseña incorrecta' })) } }\n * ```\n */\nexport function createApiError({ status = 404, message, code, fieldErrors, url }: CreateApiErrorOptions = {}): ApiError {\n const body = { state: 'error', message, code_error: code, errors: fieldErrors }\n return new ApiError(new HttpErrorResponse({ status, error: body, url }))\n}\n","import { provideHttpClient } from '@angular/common/http'\nimport { provideHttpClientTesting } from '@angular/common/http/testing'\nimport { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'\nimport { MicrositesApiConfig, provideMicrositesApi } from '@superlikers/microsites-api'\n\n/** baseUrl used by {@link provideMicrositesApiTesting}; use it to match requests in `HttpTestingController`. */\nexport const MICROSITES_API_TEST_BASE_URL = 'https://microsite.test'\n\n/**\n * Everything a test needs to use the library without a real backend:\n * the library config, `HttpClient` and `HttpTestingController`.\n *\n * @example\n * ```ts\n * TestBed.configureTestingModule({ providers: [provideMicrositesApiTesting()] })\n * const http = TestBed.inject(HttpTestingController)\n * http.expectOne(`${MICROSITES_API_TEST_BASE_URL}/sessions/logout`).flush({ state: 'success', message: 'ok' })\n * ```\n */\nexport function provideMicrositesApiTesting(config: Partial<MicrositesApiConfig> = {}): EnvironmentProviders {\n return makeEnvironmentProviders([provideHttpClient(), provideHttpClientTesting(), provideMicrositesApi({ baseUrl: MICROSITES_API_TEST_BASE_URL, ...config })])\n}\n","/*\n * Public API Surface of @superlikers/microsites-api/testing\n *\n * Test helpers for apps that use the library. Import only from spec files.\n */\n\nexport { createApiError } from './create-api-error'\nexport type { CreateApiErrorOptions } from './create-api-error'\nexport { MICROSITES_API_TEST_BASE_URL, provideMicrositesApiTesting } from './provide-microsites-api-testing'\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;AAaA;;;;;;;AAOG;SACa,cAAc,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,KAA4B,EAAE,EAAA;AAC1G,IAAA,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE;AAC/E,IAAA,OAAO,IAAI,QAAQ,CAAC,IAAI,iBAAiB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;AAC1E;;ACnBA;AACO,MAAM,4BAA4B,GAAG;AAE5C;;;;;;;;;;AAUG;AACG,SAAU,2BAA2B,CAAC,MAAA,GAAuC,EAAE,EAAA;IACnF,OAAO,wBAAwB,CAAC,CAAC,iBAAiB,EAAE,EAAE,wBAAwB,EAAE,EAAE,oBAAoB,CAAC,EAAE,OAAO,EAAE,4BAA4B,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;AAChK;;ACrBA;;;;AAIG;;ACJH;;AAEG;;"}
|