107 lines
3.0 KiB
TypeScript
107 lines
3.0 KiB
TypeScript
import { HttpClient, HttpParams } from '@angular/common/http';
|
|
import { Injector, runInInjectionContext } from '@angular/core';
|
|
import { Observable } from 'rxjs';
|
|
import { ChallengesApiService } from '../../frontend/src/app/features/challenges/challenges.service';
|
|
import { ChallengeDetail } from '../../frontend/src/app/features/challenges/challenges.pure';
|
|
|
|
interface CapturedRequest {
|
|
url: string;
|
|
params: HttpParams;
|
|
withCredentials: boolean;
|
|
}
|
|
|
|
function makeDetail(): ChallengeDetail {
|
|
return {
|
|
challenge: {
|
|
id: 'c1',
|
|
name: 'alpha',
|
|
descriptionMd: '# Alpha',
|
|
categoryId: 'cat1',
|
|
categoryAbbreviation: 'CRY',
|
|
categoryIconPath: '',
|
|
difficulty: 'LOW',
|
|
livePoints: 90,
|
|
solveCount: 1,
|
|
solvedByMe: false,
|
|
},
|
|
solvers: [
|
|
{
|
|
position: 1,
|
|
playerId: 'p1',
|
|
playerName: 'alice',
|
|
solvedAtUtc: '2025-01-01T00:00:00.000Z',
|
|
awardedPoints: 100,
|
|
basePoints: 100,
|
|
rankBonus: 0,
|
|
isFirst: true,
|
|
isSecond: false,
|
|
isThird: false,
|
|
},
|
|
],
|
|
};
|
|
}
|
|
|
|
class StubHttpClient {
|
|
public captured: CapturedRequest | null = null;
|
|
|
|
get<T>(url: string, options: { withCredentials?: boolean; params?: HttpParams | Record<string, string> }): Observable<T> {
|
|
this.captured = {
|
|
url,
|
|
params:
|
|
options.params instanceof HttpParams
|
|
? options.params
|
|
: new HttpParams({ fromObject: (options.params ?? {}) as Record<string, string> }),
|
|
withCredentials: !!options.withCredentials,
|
|
};
|
|
return new Observable<T>((subscriber) => {
|
|
subscriber.next(makeDetail() as unknown as T);
|
|
subscriber.complete();
|
|
});
|
|
}
|
|
|
|
post<T>(_url: string, _body: unknown, _options: unknown): Observable<T> {
|
|
return new Observable<T>();
|
|
}
|
|
}
|
|
|
|
describe('ChallengesApiService.getDetail', () => {
|
|
let http: StubHttpClient;
|
|
let service: ChallengesApiService;
|
|
|
|
beforeEach(() => {
|
|
http = new StubHttpClient();
|
|
const injector = Injector.create({
|
|
providers: [
|
|
{ provide: HttpClient, useValue: http },
|
|
ChallengesApiService,
|
|
],
|
|
});
|
|
service = runInInjectionContext(injector, () => injector.get(ChallengesApiService));
|
|
});
|
|
|
|
it('requests the challenge detail with include=solvers and withCredentials', (done) => {
|
|
service.getDetail('c1').subscribe(() => {
|
|
try {
|
|
expect(http.captured).not.toBeNull();
|
|
expect(http.captured!.url).toBe('/api/v1/challenges/c1');
|
|
expect(http.captured!.params.get('include')).toBe('solvers');
|
|
expect(http.captured!.withCredentials).toBe(true);
|
|
done();
|
|
} catch (err) {
|
|
done(err);
|
|
}
|
|
});
|
|
});
|
|
|
|
it('encodes the challenge id in the URL path', (done) => {
|
|
service.getDetail('c/with spaces').subscribe(() => {
|
|
try {
|
|
expect(http.captured!.url).toBe('/api/v1/challenges/c%2Fwith%20spaces');
|
|
expect(http.captured!.params.get('include')).toBe('solvers');
|
|
done();
|
|
} catch (err) {
|
|
done(err);
|
|
}
|
|
});
|
|
});
|
|
}); |