Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: removes redundant error message prefixes #213

Merged
merged 2 commits into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/classes/Auth/Auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class Auth extends PassageBase {

const { kid } = decodeProtectedHeader(jwt);
if (!kid) {
throw new Error('Could not find valid cookie for authentication. You must catch this error.');
throw new Error('kid missing in jwt header.');
}

const {
Expand Down Expand Up @@ -100,7 +100,7 @@ export class Auth extends PassageBase {

return response.magicLink;
} catch (err) {
throw await this.parseError(err, 'Could not create a magic link for this app');
throw await this.parseError(err);
}
}
}
5 changes: 2 additions & 3 deletions src/classes/PassageBase/PassageBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ export class PassageBase {
/**
* Handle errors from PassageFlex API
* @param {unknown} err error from node-fetch request
* @param {string} message optional message to include in the error
* @return {Promise<void>}
*/
protected async parseError(err: unknown, message?: string): Promise<Error> {
protected async parseError(err: unknown): Promise<Error> {
if (err instanceof ResponseError) {
throw await PassageError.fromResponseError(err, message);
throw await PassageError.fromResponseError(err);
}
return err as Error;
}
Expand Down
5 changes: 2 additions & 3 deletions src/classes/PassageError/PassageError.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@ import { ResponseError } from '../../generated';

describe('PassageError', () => {
it('should map a ResponseError to a PassageError using fromResponseError', async () => {
const message = 'Test error message';
const responseError: ResponseError = {
response: {
status: 500,
json: async () => ({ code: 'INTERNAL_SERVER_ERROR', error: 'Internal server error' }),
},
message: 'Internal server error',
} as ResponseError;
const passageError = await PassageError.fromResponseError(responseError, message);
const passageError = await PassageError.fromResponseError(responseError);

expect(passageError).toBeInstanceOf(PassageError);
expect(passageError.name).toBe('PassageError');
expect(passageError.message).toBe(`${message}: Internal server error`);
expect(passageError.message).toBe('Internal server error');
expect(passageError.errorCode).toBe('INTERNAL_SERVER_ERROR');
expect(passageError.statusCode).toBe(500);
});
Expand Down
5 changes: 2 additions & 3 deletions src/classes/PassageError/PassageError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ export class PassageError extends Error {
* @param {string} message Optional message to prefix the error message
* @return {PassageError} PassageError
*/
public static async fromResponseError(err: ResponseError, message?: string): Promise<PassageError> {
public static async fromResponseError(err: ResponseError): Promise<PassageError> {
const response: { code: string; error: string } = await err.response.json();
const formattedMessage = [message, response.error].filter(Boolean).join(': ');
return new PassageError(formattedMessage, response.code, err);
return new PassageError(response.error, response.code, err);
}
}
28 changes: 19 additions & 9 deletions src/classes/User/User.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { User } from './User';
import { PassageInstanceConfig } from '../PassageBase';
import { UsersApi, ResponseError, ListPaginatedUsersResponse, Configuration } from '../../generated';
import { PassageUser } from './types';
import { PassageError } from '../PassageError';

jest.mock('../../generated/apis');

Expand Down Expand Up @@ -39,24 +40,33 @@ describe('User class', () => {
});

it('should throw an error if get user by identifier fails', async () => {
usersApiMock.listPaginatedUsers.mockRejectedValue(
const responseError = new ResponseError(
{
status: 502,
json: async () => ({ code: 'error_code', error: 'Bad gateway' }),
} as Response,
'Error',
);
const passageError = await PassageError.fromResponseError(responseError);
usersApiMock.listPaginatedUsers.mockRejectedValue(responseError);

await expect(user.getByIdentifier('[email protected]')).rejects.toThrow(passageError);
await expect(user.getByIdentifier('[email protected]')).rejects.toThrow('Bad gateway');
});

it('should throw an error if get user by identifier returns an empty array', async () => {
const passageError = await PassageError.fromResponseError(
new ResponseError(
{
status: 404,
json: async () => ({ code: 'NOT_FOUND', error: 'Resource not found' }),
json: async () => ({ code: 'user_not_found', error: 'User not found.' }),
} as Response,
'Error',
),
);
await expect(user.getByIdentifier('[email protected]')).rejects.toThrow(Error);
await expect(user.getByIdentifier('[email protected]')).rejects.toThrow(
'Could not fetch user by identifier: Resource not found',
);
});

it('should throw an error if get user by identifier returns an empty array', async () => {
usersApiMock.listPaginatedUsers.mockResolvedValue({ users: [] } as unknown as ListPaginatedUsersResponse);
await expect(user.getByIdentifier('[email protected]')).rejects.toThrow(Error);
await expect(user.getByIdentifier('[email protected]')).rejects.toThrow(passageError);
await expect(user.getByIdentifier('[email protected]')).rejects.toThrow('User not found.');
});
});
26 changes: 14 additions & 12 deletions src/classes/User/User.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PassageBase, PassageInstanceConfig } from '../PassageBase';
import { TokensApi, UserDevicesApi, UsersApi, WebAuthnDevices } from '../../generated';
import { ResponseError, TokensApi, UserDevicesApi, UsersApi, WebAuthnDevices } from '../../generated';
import { CreateUserArgs, PassageUser, UpdateUserArgs } from './types';

/**
Expand Down Expand Up @@ -40,7 +40,7 @@ export class User extends PassageBase {

return response.user;
} catch (err) {
throw await this.parseError(err, 'Could not fetch user');
throw await this.parseError(err);
}
}

Expand All @@ -64,12 +64,14 @@ export class User extends PassageBase {

const users = response.users;
if (!users.length) {
throw new Error('User not found.');
throw new ResponseError(
new Response('{"code":"user_not_found","error":"User not found."}', { status: 404 }),
);
}

return this.get(users[0].id);
} catch (err) {
throw await this.parseError(err, 'Could not fetch user by identifier');
throw await this.parseError(err);
}
}

Expand All @@ -91,7 +93,7 @@ export class User extends PassageBase {
});
return response.user;
} catch (err) {
throw await this.parseError(err, 'Could not activate user');
throw await this.parseError(err);
}
}

Expand All @@ -114,7 +116,7 @@ export class User extends PassageBase {

return response.user;
} catch (err) {
throw await this.parseError(err, 'Could not deactivate user');
throw await this.parseError(err);
}
}

Expand All @@ -139,7 +141,7 @@ export class User extends PassageBase {

return response.user;
} catch (err) {
throw await this.parseError(err, 'Could not update user');
throw await this.parseError(err);
}
}

Expand All @@ -162,7 +164,7 @@ export class User extends PassageBase {

return response.user;
} catch (err) {
throw await this.parseError(err, 'Could not create user');
throw await this.parseError(err);
}
}

Expand All @@ -184,7 +186,7 @@ export class User extends PassageBase {
});
return true;
} catch (err) {
throw await this.parseError(err, 'Could not delete user');
throw await this.parseError(err);
}
}

Expand All @@ -207,7 +209,7 @@ export class User extends PassageBase {

return response.devices;
} catch (err) {
throw await this.parseError(err, "Could not fetch user's devices:");
throw await this.parseError(err);
}
}

Expand Down Expand Up @@ -236,7 +238,7 @@ export class User extends PassageBase {

return true;
} catch (err) {
throw await this.parseError(err, "Could not delete user's device:");
throw await this.parseError(err);
}
}

Expand All @@ -258,7 +260,7 @@ export class User extends PassageBase {
});
return true;
} catch (err) {
throw await this.parseError(err, "Could not revoke user's refresh tokens:");
throw await this.parseError(err);
}
}
}
Loading