BREAKING CHANGE(acme): Replace external acme-client with a built-in RFC8555-compliant ACME implementation and update public APIs accordingly
This commit is contained in:
103
test/test.acme-error.ts
Normal file
103
test/test.acme-error.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
import { AcmeError } from '../ts/acme/acme.classes.error.js';
|
||||
|
||||
// --- Basic error properties ---
|
||||
|
||||
tap.test('AcmeError extends Error', async () => {
|
||||
const err = new AcmeError({ status: 400 });
|
||||
expect(err).toBeInstanceOf(Error);
|
||||
expect(err).toBeInstanceOf(AcmeError);
|
||||
});
|
||||
|
||||
tap.test('AcmeError has correct name', async () => {
|
||||
const err = new AcmeError({ status: 400 });
|
||||
expect(err.name).toEqual('AcmeError');
|
||||
});
|
||||
|
||||
tap.test('message includes type, status, url, and detail', async () => {
|
||||
const err = new AcmeError({
|
||||
status: 403,
|
||||
type: 'urn:ietf:params:acme:error:unauthorized',
|
||||
detail: 'Account is deactivated',
|
||||
url: 'https://acme.example/order/1',
|
||||
});
|
||||
expect(err.message).toInclude('403');
|
||||
expect(err.message).toInclude('urn:ietf:params:acme:error:unauthorized');
|
||||
expect(err.message).toInclude('https://acme.example/order/1');
|
||||
expect(err.message).toInclude('Account is deactivated');
|
||||
});
|
||||
|
||||
tap.test('preserves all properties including subproblems', async () => {
|
||||
const subproblems = [
|
||||
{ type: 'urn:ietf:params:acme:error:caa', detail: 'CAA record prevents issuance', identifier: { type: 'dns', value: 'example.com' } },
|
||||
];
|
||||
const err = new AcmeError({
|
||||
status: 403,
|
||||
type: 'urn:ietf:params:acme:error:unauthorized',
|
||||
detail: 'Forbidden',
|
||||
subproblems,
|
||||
url: 'https://acme.example/chall/1',
|
||||
retryAfter: 30,
|
||||
});
|
||||
expect(err.status).toEqual(403);
|
||||
expect(err.type).toEqual('urn:ietf:params:acme:error:unauthorized');
|
||||
expect(err.detail).toEqual('Forbidden');
|
||||
expect(err.subproblems.length).toEqual(1);
|
||||
expect(err.subproblems[0].type).toEqual('urn:ietf:params:acme:error:caa');
|
||||
expect(err.url).toEqual('https://acme.example/chall/1');
|
||||
expect(err.retryAfter).toEqual(30);
|
||||
});
|
||||
|
||||
tap.test('default values for optional fields', async () => {
|
||||
const err = new AcmeError({ status: 500 });
|
||||
expect(err.type).toEqual('');
|
||||
expect(err.detail).toEqual('');
|
||||
expect(err.subproblems).toEqual([]);
|
||||
expect(err.url).toEqual('');
|
||||
expect(err.retryAfter).toEqual(0);
|
||||
});
|
||||
|
||||
// --- isRateLimited ---
|
||||
|
||||
tap.test('isRateLimited is true for status 429', async () => {
|
||||
const err = new AcmeError({ status: 429 });
|
||||
expect(err.isRateLimited).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('isRateLimited is true for rateLimited type URN', async () => {
|
||||
const err = new AcmeError({
|
||||
status: 403,
|
||||
type: 'urn:ietf:params:acme:error:rateLimited',
|
||||
});
|
||||
expect(err.isRateLimited).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('isRateLimited is false for regular 400', async () => {
|
||||
const err = new AcmeError({ status: 400, type: 'urn:ietf:params:acme:error:malformed' });
|
||||
expect(err.isRateLimited).toBeFalse();
|
||||
});
|
||||
|
||||
// --- isRetryable ---
|
||||
|
||||
tap.test('isRetryable is true for 429', async () => {
|
||||
const err = new AcmeError({ status: 429 });
|
||||
expect(err.isRetryable).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('isRetryable is true for 503 and 500', async () => {
|
||||
expect(new AcmeError({ status: 503 }).isRetryable).toBeTrue();
|
||||
expect(new AcmeError({ status: 500 }).isRetryable).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('isRetryable is true for badNonce type', async () => {
|
||||
const err = new AcmeError({ status: 400, type: 'urn:ietf:params:acme:error:badNonce' });
|
||||
expect(err.isRetryable).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('isRetryable is false for 403, 404, 409', async () => {
|
||||
expect(new AcmeError({ status: 403 }).isRetryable).toBeFalse();
|
||||
expect(new AcmeError({ status: 404 }).isRetryable).toBeFalse();
|
||||
expect(new AcmeError({ status: 409 }).isRetryable).toBeFalse();
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
Reference in New Issue
Block a user