Skip to content

Commit

Permalink
fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
MarvinOehlerkingCap committed Jan 15, 2024
1 parent 2e3bcd5 commit 678997e
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class LoginResponse {
this.client = props.client;
this.client_id = props.client_id;
this.challenge = props.challenge;
this.oidc_context = props.oidc_context;
this.oidc_context = new OidcContextResponse(props.oidc_context);
this.request_url = props.request_url;
this.skip = props.skip;
this.requested_access_token_audience = props.requested_access_token_audience;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Optional } from '@nestjs/common';
import { ApiProperty } from '@nestjs/swagger';

export class OidcContextResponse {
Expand All @@ -22,7 +21,6 @@ export class OidcContextResponse {
@ApiProperty()
login_hint: string;

@Optional()
@ApiProperty()
ui_locales: string[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { ObjectId } from '@mikro-orm/mongodb';
import { ForbiddenException } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import {
AcceptConsentRequestBody,
IdToken,
ProviderConsentResponse,
ProviderRedirectResponse,
RejectRequestBody,
} from '../domain';
import { IdTokenService } from '../domain/service/id-token.service';
import { OauthProviderService } from '../domain/service/oauth-provider.service';
import {
acceptConsentRequestBodyFactory,
idTokenFactory,
providerConsentResponseFactory,
rejectRequestBodyFactory,
} from '../testing';
import { OauthProviderConsentFlowUc } from './oauth-provider.consent-flow.uc';

describe('OauthProviderConsentFlowUc', () => {
let module: TestingModule;
let uc: OauthProviderConsentFlowUc;

let oauthProviderService: DeepMocked<OauthProviderService>;
let idTokenService: DeepMocked<IdTokenService>;

beforeAll(async () => {
module = await Test.createTestingModule({
providers: [
OauthProviderConsentFlowUc,
{
provide: OauthProviderService,
useValue: createMock<OauthProviderService>(),
},
{
provide: IdTokenService,
useValue: createMock<IdTokenService>(),
},
],
}).compile();

uc = module.get(OauthProviderConsentFlowUc);
oauthProviderService = module.get(OauthProviderService);
idTokenService = module.get(IdTokenService);
});

afterAll(async () => {
await module.close();
});

afterEach(() => {
jest.clearAllMocks();
});

describe('getConsentRequest', () => {
describe('when fetching a consent request', () => {
const setup = () => {
const challenge = 'challenge';
const consentResponse: ProviderConsentResponse = providerConsentResponseFactory.build();

oauthProviderService.getConsentRequest.mockResolvedValueOnce(consentResponse);

return {
challenge,
consentResponse,
};
};

it('should call the external provider', async () => {
const { challenge } = setup();

await uc.getConsentRequest(challenge);

expect(oauthProviderService.getConsentRequest).toHaveBeenCalledWith(challenge);
});

it('should return the consent request', async () => {
const { challenge, consentResponse } = setup();

const result: ProviderConsentResponse = await uc.getConsentRequest(challenge);

expect(result).toEqual(consentResponse);
});
});
});

describe('patchConsentRequest', () => {
describe('when accepting a consent request', () => {
const setup = () => {
const userId = new ObjectId().toHexString();
const challenge = 'challenge';
const acceptConsentRequestBody: AcceptConsentRequestBody = acceptConsentRequestBodyFactory.build();
const consentResponse: ProviderConsentResponse = providerConsentResponseFactory.build({ subject: userId });
const idToken: IdToken = idTokenFactory.build();
const redirectResponse: ProviderRedirectResponse = { redirect_to: 'mockredirect' };

oauthProviderService.getConsentRequest.mockResolvedValueOnce(consentResponse);
idTokenService.createIdToken.mockResolvedValueOnce(idToken);
oauthProviderService.acceptConsentRequest.mockResolvedValueOnce(redirectResponse);

return {
userId,
challenge,
consentResponse,
acceptConsentRequestBody,
idToken,
redirectResponse,
};
};

it('should request a consent from the external provider', async () => {
const { userId, challenge, acceptConsentRequestBody } = setup();

await uc.patchConsentRequest(userId, challenge, true, acceptConsentRequestBody);

expect(oauthProviderService.getConsentRequest).toHaveBeenCalledWith(challenge);
});

it('should create an id token', async () => {
const { userId, challenge, acceptConsentRequestBody, consentResponse } = setup();

await uc.patchConsentRequest(userId, challenge, true, acceptConsentRequestBody);

expect(idTokenService.createIdToken).toHaveBeenCalledWith(
userId,
consentResponse.requested_scope,
consentResponse.client.client_id
);
});

it('should accept the consent', async () => {
const { userId, challenge, acceptConsentRequestBody, idToken } = setup();

await uc.patchConsentRequest(userId, challenge, true, acceptConsentRequestBody);

expect(oauthProviderService.acceptConsentRequest).toHaveBeenCalledWith(challenge, {
...acceptConsentRequestBody,
session: { id_token: idToken },
});
});

it('should return a redirect', async () => {
const { userId, challenge, acceptConsentRequestBody, redirectResponse } = setup();

const result: ProviderRedirectResponse = await uc.patchConsentRequest(
userId,
challenge,
true,
acceptConsentRequestBody
);

expect(result).toEqual(redirectResponse);
});
});

describe('when rejecting a consent request', () => {
const setup = () => {
const userId = new ObjectId().toHexString();
const challenge = 'challenge';
const rejectRequestBody: RejectRequestBody = rejectRequestBodyFactory.build();
const consentResponse: ProviderConsentResponse = providerConsentResponseFactory.build({ subject: userId });
const redirectResponse: ProviderRedirectResponse = { redirect_to: 'mockredirect' };

oauthProviderService.getConsentRequest.mockResolvedValueOnce(consentResponse);
oauthProviderService.rejectConsentRequest.mockResolvedValueOnce(redirectResponse);

return {
userId,
challenge,
consentResponse,
rejectRequestBody,
redirectResponse,
};
};

it('should request a consent from the external provider', async () => {
const { userId, challenge, rejectRequestBody } = setup();

await uc.patchConsentRequest(userId, challenge, false, rejectRequestBody);

expect(oauthProviderService.getConsentRequest).toHaveBeenCalledWith(challenge);
});

it('should reject the consent', async () => {
const { userId, challenge, rejectRequestBody } = setup();

await uc.patchConsentRequest(userId, challenge, false, rejectRequestBody);

expect(oauthProviderService.rejectConsentRequest).toHaveBeenCalledWith(challenge, rejectRequestBody);
});

it('should return a redirect', async () => {
const { userId, challenge, rejectRequestBody, redirectResponse } = setup();

const result: ProviderRedirectResponse = await uc.patchConsentRequest(
userId,
challenge,
false,
rejectRequestBody
);

expect(result).toEqual(redirectResponse);
});
});

describe('when the user is not the subject of the challenge', () => {
const setup = () => {
const userId = new ObjectId().toHexString();
const challenge = 'challenge';
const acceptConsentRequestBody: AcceptConsentRequestBody = acceptConsentRequestBodyFactory.build();
const consentResponse: ProviderConsentResponse = providerConsentResponseFactory.build({
subject: 'notTheUserId',
});

oauthProviderService.getConsentRequest.mockResolvedValueOnce(consentResponse);

return {
userId,
challenge,
consentResponse,
acceptConsentRequestBody,
};
};

it('should throw an error', async () => {
const { userId, challenge, acceptConsentRequestBody } = setup();

await expect(uc.patchConsentRequest(userId, challenge, true, acceptConsentRequestBody)).rejects.toThrow(
ForbiddenException
);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { HttpService } from '@nestjs/axios';
import { Test, TestingModule } from '@nestjs/testing';
import { axiosResponseFactory } from '@shared/testing';
import { axiosErrorFactory, axiosResponseFactory } from '@shared/testing';
import { AxiosRequestConfig } from 'axios';
import { of } from 'rxjs';
import { of, throwError } from 'rxjs';
import { OauthProviderFeatures } from '../../oauth-provider-config';
import {
acceptConsentRequestBodyFactory,
Expand All @@ -15,6 +15,7 @@ import {
providerOauthClientFactory,
rejectRequestBodyFactory,
} from '../../testing';
import { HydraOauthFailedLoggableException } from '../error';
import {
AcceptConsentRequestBody,
AcceptLoginRequestBody,
Expand Down Expand Up @@ -152,6 +153,24 @@ describe('HydraService', () => {
expect(result).toEqual(data);
});
});

describe('when hydra returns an axios error', () => {
it('should throw an error', async () => {
httpService.request.mockReturnValueOnce(throwError(() => axiosErrorFactory.build()));

await expect(service.listOAuth2Clients()).rejects.toThrow(HydraOauthFailedLoggableException);
});
});

describe('when an unknown error occurs during the request', () => {
it('should throw an error', async () => {
const error = new Error();

httpService.request.mockReturnValueOnce(throwError(() => error));

await expect(service.listOAuth2Clients()).rejects.toThrow(error);
});
});
});

describe('getOAuth2Client', () => {
Expand Down

0 comments on commit 678997e

Please sign in to comment.