• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

oprajs / opra / 14419802659

12 Apr 2025 12:55PM UTC coverage: 82.088% (+4.2%) from 77.908%
14419802659

push

github

web-flow
Merge pull request #27 from oprajs/dev

Dev

3458 of 4432 branches covered (78.02%)

Branch coverage included in aggregate %.

16 of 16 new or added lines in 10 files covered. (100.0%)

1793 existing lines in 129 files now uncovered.

29424 of 35625 relevant lines covered (82.59%)

183.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/packages/angular/src/angular-backend.ts
UNCOV
1
import { HttpContext, HttpHeaders, HttpParams } from '@angular/common/http';
×
UNCOV
2
import * as Angular from '@angular/common/http';
×
UNCOV
3
import typeIs from '@browsery/type-is';
×
UNCOV
4
import {
×
UNCOV
5
  HttpBackend,
×
UNCOV
6
  type HttpDownloadProgressEvent,
×
UNCOV
7
  type HttpEvent,
×
UNCOV
8
  HttpEventType,
×
UNCOV
9
  HttpResponse,
×
UNCOV
10
  type HttpResponseEvent,
×
UNCOV
11
  type HttpResponseHeaderEvent,
×
UNCOV
12
  type HttpSentEvent,
×
UNCOV
13
  type HttpUploadProgressEvent,
×
UNCOV
14
} from '@opra/client';
×
UNCOV
15
import { isBlob } from '@opra/common';
×
UNCOV
16
import { Observable } from 'rxjs';
×
UNCOV
17
import { isReadableStreamLike } from 'rxjs/internal/util/isReadableStreamLike';
×
UNCOV
18
import type { StrictOmit } from 'ts-gems';
×
UNCOV
19

×
UNCOV
20
/**
×
UNCOV
21
 *
×
UNCOV
22
 * @class AngularBackend
×
UNCOV
23
 */
×
UNCOV
24
export class AngularBackend extends HttpBackend {
×
UNCOV
25
  defaults: AngularBackend.RequestDefaults;
×
UNCOV
26

×
UNCOV
27
  constructor(
×
UNCOV
28
    readonly httpClient: Angular.HttpClient,
×
UNCOV
29
    serviceUrl: string,
×
UNCOV
30
    options?: AngularBackend.Options,
×
UNCOV
31
  ) {
×
UNCOV
32
    super(serviceUrl, options);
×
UNCOV
33
    this.defaults = {
×
UNCOV
34
      ...options?.defaults,
×
UNCOV
35
      headers:
×
UNCOV
36
        options?.defaults?.headers instanceof Headers
×
UNCOV
37
          ? options?.defaults?.headers
×
UNCOV
38
          : new Headers(options?.defaults?.headers),
×
UNCOV
39
      params:
×
UNCOV
40
        options?.defaults?.params instanceof URLSearchParams
×
UNCOV
41
          ? options?.defaults?.params
×
UNCOV
42
          : new URLSearchParams(options?.defaults?.params),
×
UNCOV
43
    };
×
UNCOV
44
  }
×
UNCOV
45

×
UNCOV
46
  handle(init: AngularBackend.RequestInit): Observable<HttpEvent> {
×
47
    const requestInit = this.prepareRequest(init);
×
48
    const request = new Angular.HttpRequest(
×
UNCOV
49
      requestInit.method,
×
UNCOV
50
      requestInit.url.toString(),
×
UNCOV
51
      {
×
UNCOV
52
        ...requestInit,
×
UNCOV
53
        headers: new HttpHeaders(requestInit.headers),
×
UNCOV
54
      },
×
UNCOV
55
    );
×
UNCOV
56

×
57
    const _this = this;
×
58
    return new Observable<HttpEvent>(subscriber => {
×
UNCOV
59
      // Send request
×
60
      this.send(request).subscribe({
×
UNCOV
61
        next(event) {
×
62
          if (event.type === Angular.HttpEventType.Sent) {
×
UNCOV
63
            // Emit 'Sent' event
×
64
            subscriber.next({
×
UNCOV
65
              type: HttpEventType.Sent,
×
UNCOV
66
              request,
×
UNCOV
67
            } satisfies HttpSentEvent);
×
68
            return;
×
UNCOV
69
          }
×
UNCOV
70

×
71
          if (event.type === Angular.HttpEventType.ResponseHeader) {
×
UNCOV
72
            // Emit 'ResponseHeader' event
×
73
            const headersResponse = _this.createResponse({
×
UNCOV
74
              url: request.url,
×
UNCOV
75
              headers: requestInit.headers,
×
UNCOV
76
              status: event.status,
×
UNCOV
77
              statusText: event.statusText,
×
UNCOV
78
              hasBody:
×
UNCOV
79
                event.headers.has('Content-Type') ||
×
UNCOV
80
                event.headers.has('Content-Length'),
×
UNCOV
81
            }) as HttpResponse<never>;
×
82
            subscriber.next({
×
UNCOV
83
              request,
×
UNCOV
84
              type: HttpEventType.ResponseHeader,
×
UNCOV
85
              response: headersResponse,
×
UNCOV
86
            } satisfies HttpResponseHeaderEvent);
×
87
            return;
×
UNCOV
88
          }
×
UNCOV
89

×
90
          if (event.type === Angular.HttpEventType.DownloadProgress) {
×
UNCOV
91
            // Emit 'DownloadProgress' event
×
92
            subscriber.next({
×
UNCOV
93
              request,
×
UNCOV
94
              type: HttpEventType.DownloadProgress,
×
UNCOV
95
              loaded: event.loaded,
×
UNCOV
96
              total: event.total,
×
UNCOV
97
            } satisfies HttpDownloadProgressEvent);
×
UNCOV
98
          }
×
UNCOV
99

×
100
          if (event.type === Angular.HttpEventType.UploadProgress) {
×
UNCOV
101
            // Emit 'UploadProgress' event
×
102
            subscriber.next({
×
UNCOV
103
              request,
×
UNCOV
104
              type: HttpEventType.UploadProgress,
×
UNCOV
105
              loaded: event.loaded,
×
UNCOV
106
              total: event.total,
×
UNCOV
107
            } satisfies HttpUploadProgressEvent);
×
UNCOV
108
          }
×
UNCOV
109

×
110
          if (event.type === Angular.HttpEventType.Response) {
×
111
            const headers = new Headers();
×
112
            event.headers
×
UNCOV
113
              .keys()
×
114
              .forEach(k => headers.set(k, event.headers.get(k) || ''));
×
115
            const response = _this.createResponse({
×
UNCOV
116
              url: request.url,
×
UNCOV
117
              headers,
×
UNCOV
118
              status: event.status,
×
UNCOV
119
              statusText: event.statusText,
×
UNCOV
120
              hasBody: !!event.body,
×
UNCOV
121
              body: event.body,
×
UNCOV
122
            });
×
UNCOV
123
            // Emit 'Response' event
×
124
            subscriber.next({
×
UNCOV
125
              type: HttpEventType.Response,
×
UNCOV
126
              request,
×
UNCOV
127
              response,
×
UNCOV
128
            } satisfies HttpResponseEvent);
×
UNCOV
129
          }
×
UNCOV
130
        },
×
UNCOV
131
        error(error) {
×
132
          subscriber.error(error);
×
UNCOV
133
        },
×
UNCOV
134
        complete() {
×
135
          subscriber.complete();
×
UNCOV
136
        },
×
UNCOV
137
      });
×
UNCOV
138
    });
×
UNCOV
139
  }
×
UNCOV
140

×
UNCOV
141
  protected send(request: Angular.HttpRequest<any>) {
×
142
    return this.httpClient.request(request);
×
UNCOV
143
  }
×
UNCOV
144

×
UNCOV
145
  protected prepareRequest(
×
UNCOV
146
    init: AngularBackend.RequestInit,
×
UNCOV
147
  ): AngularBackend.RequestInit {
×
148
    const headers = init.headers || new Headers();
×
149
    const requestInit: AngularBackend.RequestInit = {
×
UNCOV
150
      ...init,
×
UNCOV
151
      headers,
×
UNCOV
152
    };
×
153
    this.defaults.headers.forEach((val, key) => {
×
154
      if (!headers.has(key)) headers.set(key, val);
×
UNCOV
155
    });
×
156
    const url = new URL(requestInit.url, this.serviceUrl);
×
157
    if (this.defaults.params.size) {
×
158
      this.defaults.params.forEach((val, key) => {
×
159
        if (!url.searchParams.has(key)) url.searchParams.set(key, val);
×
UNCOV
160
      });
×
161
      requestInit.url = url.toString();
×
UNCOV
162
    }
×
163
    if (requestInit.body) {
×
UNCOV
164
      let body: any;
×
UNCOV
165
      let contentType: string;
×
166
      if (
×
UNCOV
167
        typeof requestInit.body === 'string' ||
×
UNCOV
168
        typeof requestInit.body === 'number' ||
×
UNCOV
169
        typeof requestInit.body === 'boolean'
×
UNCOV
170
      ) {
×
171
        contentType = 'text/plain; charset=UTF-8"';
×
172
        body = String(requestInit.body);
×
173
        headers.delete('Content-Size');
×
174
      } else if (isReadableStreamLike(requestInit.body)) {
×
175
        contentType = 'application/octet-stream';
×
176
        body = requestInit.body;
×
177
      } else if (Buffer.isBuffer(requestInit.body)) {
×
178
        contentType = 'application/octet-stream';
×
179
        body = requestInit.body;
×
180
        headers.set('Content-Size', String(requestInit.body.length));
×
181
      } else if (isBlob(requestInit.body)) {
×
182
        contentType = requestInit.body.type || 'application/octet-stream';
×
183
        body = requestInit.body;
×
184
        headers.set('Content-Size', String(requestInit.body.size));
×
UNCOV
185
      } else {
×
186
        contentType = 'application/json';
×
187
        body = JSON.stringify(requestInit.body);
×
188
        headers.delete('Content-Size');
×
UNCOV
189
      }
×
190
      if (!headers.has('Content-Type') && contentType)
×
191
        headers.set('Content-Type', contentType);
×
192
      requestInit.body = body;
×
UNCOV
193
    }
×
194
    return requestInit;
×
UNCOV
195
  }
×
UNCOV
196

×
UNCOV
197
  protected createResponse(init: HttpResponse.Initiator): HttpResponse {
×
198
    return new HttpResponse(init);
×
UNCOV
199
  }
×
UNCOV
200

×
UNCOV
201
  protected async parseBody(fetchResponse: Response): Promise<any> {
×
UNCOV
202
    let body: any;
×
203
    const contentType = fetchResponse.headers.get('Content-Type') || '';
×
204
    if (typeIs.is(contentType, ['json', 'application/*+json'])) {
×
205
      body = await fetchResponse.json();
×
206
      if (typeof body === 'string') body = JSON.parse(body);
×
207
    } else if (typeIs.is(contentType, ['text']))
×
208
      body = await fetchResponse.text();
×
209
    else if (typeIs.is(contentType, ['multipart']))
×
210
      body = await fetchResponse.formData();
×
UNCOV
211
    else {
×
212
      const buf = await fetchResponse.arrayBuffer();
×
213
      if (buf.byteLength) body = buf;
×
UNCOV
214
    }
×
215
    return body;
×
UNCOV
216
  }
×
UNCOV
217
}
×
UNCOV
218

×
UNCOV
219
/**
×
UNCOV
220
 * @namespace AngularBackend
×
UNCOV
221
 */
×
UNCOV
222
export namespace AngularBackend {
×
UNCOV
223
  export interface Options extends HttpBackend.Options {
×
UNCOV
224
    defaults?: RequestDefaults;
×
UNCOV
225
  }
×
UNCOV
226

×
UNCOV
227
  export interface RequestInit extends HttpBackend.RequestInit {
×
UNCOV
228
    context?: HttpContext;
×
UNCOV
229
    reportProgress?: boolean;
×
UNCOV
230
    params?: HttpParams;
×
UNCOV
231
    responseType?: 'arraybuffer' | 'blob' | 'json' | 'text';
×
UNCOV
232
    withCredentials?: boolean;
×
UNCOV
233
  }
×
UNCOV
234

×
UNCOV
235
  export interface RequestOptions
×
UNCOV
236
    extends Pick<
×
UNCOV
237
      RequestInit,
×
UNCOV
238
      'context' | 'reportProgress' | 'withCredentials'
×
UNCOV
239
    > {}
×
UNCOV
240

×
UNCOV
241
  export type RequestDefaults = StrictOmit<RequestOptions, 'context'> & {
×
UNCOV
242
    headers: Headers;
×
UNCOV
243
    params: URLSearchParams;
×
UNCOV
244
  };
×
UNCOV
245
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc