Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
214 lines
5.0 KiB
TypeScript
214 lines
5.0 KiB
TypeScript
import { expect } from 'vitest';
|
|
|
|
/**
|
|
* Options for error assertion
|
|
*/
|
|
export interface ErrorAssertionOptions {
|
|
/**
|
|
* Expected error message
|
|
* If provided, will check exact message match
|
|
*/
|
|
message?: string;
|
|
|
|
/**
|
|
* Expected error message pattern
|
|
* If provided, will check if message matches regex
|
|
*/
|
|
messagePattern?: RegExp;
|
|
|
|
/**
|
|
* Expected error name/type
|
|
* @default 'Error'
|
|
*/
|
|
name?: string;
|
|
|
|
/**
|
|
* Whether to check error properties
|
|
*/
|
|
properties?: Record<string, unknown>;
|
|
}
|
|
|
|
/**
|
|
* Asserts that a function throws an error
|
|
* @param fn Function that should throw
|
|
* @param options Error assertion options
|
|
*/
|
|
export async function expectError(
|
|
fn: () => unknown | Promise<unknown>,
|
|
options: ErrorAssertionOptions = {}
|
|
): Promise<void> {
|
|
const {
|
|
message,
|
|
messagePattern,
|
|
name = 'Error',
|
|
properties
|
|
} = options;
|
|
|
|
try {
|
|
await fn();
|
|
throw new Error('Expected function to throw an error');
|
|
} catch (err) {
|
|
if (!(err instanceof Error)) {
|
|
throw new Error(`Expected error to be instance of Error, got ${typeof err}`);
|
|
}
|
|
|
|
const error = err as Error;
|
|
|
|
// Check error type
|
|
expect(error).toBeInstanceOf(Error);
|
|
expect(error.constructor.name).toBe(name);
|
|
|
|
// Check error message
|
|
if (message) {
|
|
expect(error.message).toBe(message);
|
|
}
|
|
if (messagePattern) {
|
|
expect(error.message).toMatch(messagePattern);
|
|
}
|
|
|
|
// Check error properties
|
|
if (properties) {
|
|
Object.entries(properties).forEach(([key, value]) => {
|
|
expect(error).toHaveProperty(key, value);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates error assertion helpers for specific error types
|
|
* @param errorType Error class to test for
|
|
* @returns Object with error assertion helpers
|
|
*/
|
|
export function createErrorAssertions<T extends Error>(errorType: new (...args: any[]) => T) {
|
|
return {
|
|
/**
|
|
* Asserts that a function throws the specific error type
|
|
*/
|
|
expectError: async (
|
|
fn: () => unknown | Promise<unknown>,
|
|
options: Omit<ErrorAssertionOptions, 'name'> = {}
|
|
) => {
|
|
await expectError(fn, {
|
|
...options,
|
|
name: errorType.name
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Creates an assertion for a specific error message
|
|
*/
|
|
expectErrorMessage: (message: string) =>
|
|
async (fn: () => unknown | Promise<unknown>) => {
|
|
await expectError(fn, {
|
|
message,
|
|
name: errorType.name
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Creates an assertion for a specific error pattern
|
|
*/
|
|
expectErrorPattern: (pattern: RegExp) =>
|
|
async (fn: () => unknown | Promise<unknown>) => {
|
|
await expectError(fn, {
|
|
messagePattern: pattern,
|
|
name: errorType.name
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Common error patterns for validation
|
|
*/
|
|
export const ValidationPatterns = {
|
|
Required: (field: string) => new RegExp(`${field}.*required`, 'i'),
|
|
Invalid: (field: string) => new RegExp(`${field}.*invalid`, 'i'),
|
|
NotFound: (entity: string) => new RegExp(`${entity}.*not found`, 'i'),
|
|
Duplicate: (field: string) => new RegExp(`${field}.*already exists`, 'i'),
|
|
Permission: () => /permission denied|unauthorized|forbidden/i,
|
|
};
|
|
|
|
/**
|
|
* Creates test cases for common validation errors
|
|
* @param execute Function that executes the operation
|
|
* @param field Field being validated
|
|
* @returns Object with test case functions
|
|
*/
|
|
export function createValidationTests(
|
|
execute: (value: any) => Promise<unknown>,
|
|
field: string
|
|
) {
|
|
return {
|
|
/**
|
|
* Tests that the field is required
|
|
*/
|
|
testRequired: async () => {
|
|
await expectError(
|
|
() => execute(null),
|
|
{
|
|
messagePattern: ValidationPatterns.Required(field)
|
|
}
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Tests that the field must be valid
|
|
* @param invalidValue Invalid value to test
|
|
*/
|
|
testInvalid: async (invalidValue: any) => {
|
|
await expectError(
|
|
() => execute(invalidValue),
|
|
{
|
|
messagePattern: ValidationPatterns.Invalid(field)
|
|
}
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Tests that the field must be unique
|
|
* @param duplicateValue Value that already exists
|
|
*/
|
|
testUnique: async (duplicateValue: any) => {
|
|
await expectError(
|
|
() => execute(duplicateValue),
|
|
{
|
|
messagePattern: ValidationPatterns.Duplicate(field)
|
|
}
|
|
);
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Helper to test permission-related errors
|
|
* @param execute Function that should be denied
|
|
*/
|
|
export async function expectPermissionDenied(
|
|
execute: () => Promise<unknown>
|
|
): Promise<void> {
|
|
await expectError(
|
|
execute,
|
|
{
|
|
messagePattern: ValidationPatterns.Permission()
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Helper to test entity not found errors
|
|
* @param execute Function that should fail to find entity
|
|
* @param entityType Type of entity (e.g., 'User', 'Project')
|
|
*/
|
|
export async function expectNotFound(
|
|
execute: () => Promise<unknown>,
|
|
entityType: string
|
|
): Promise<void> {
|
|
await expectError(
|
|
execute,
|
|
{
|
|
messagePattern: ValidationPatterns.NotFound(entityType)
|
|
}
|
|
);
|
|
} |