Skip to content

Commit 1933d67

Browse files
refactor(e2e): replace expect+type guard with custom assertion function
Replace expect().toBeDefined() + if (!value) return; pattern with custom assertDefined<T>() function using TypeScript's asserts keyword. Benefits: - Single line instead of two - Better error messages with value name - Type narrowing via assertion signature - More idiomatic TypeScript Co-authored-by: Lars Gyrup Brink Nielsen <[email protected]>
1 parent 17ee79a commit 1933d67

File tree

1 file changed

+34
-18
lines changed

1 file changed

+34
-18
lines changed

packages/workspace-e2e/src/workspace.suite.spec.ts

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,31 @@ expect.extend({
6363
},
6464
});
6565

66+
/**
67+
* Custom TypeScript assertion function to validate that a value is defined.
68+
* Throws an error with a helpful message if the value is undefined or null.
69+
*
70+
* This function provides both runtime validation and TypeScript type narrowing,
71+
* eliminating the need for separate `expect().toBeDefined()` and `if (!value) return;` patterns.
72+
*
73+
* @param value - The value to check
74+
* @param name - The name of the value (used in error messages)
75+
* @throws {Error} If the value is undefined or null
76+
*
77+
* @example
78+
* assertDefined(sharedWorkspace, 'sharedWorkspace');
79+
* // TypeScript now knows sharedWorkspace is not undefined
80+
* console.log(sharedWorkspace.path);
81+
*/
82+
function assertDefined<T>(
83+
value: T,
84+
name: string,
85+
): asserts value is NonNullable<T> {
86+
if (value === undefined || value === null) {
87+
throw new Error(`Expected ${name} to be defined, but it was ${value}`);
88+
}
89+
}
90+
6691
/**
6792
* Orchestrator State
6893
*
@@ -352,8 +377,7 @@ describe('E2E Test Suite (Orchestrator)', () => {
352377
return;
353378
}
354379

355-
expect(sharedWorkspace).toBeDefined();
356-
if (!sharedWorkspace) return; // Type guard for TypeScript
380+
assertDefined(sharedWorkspace, 'sharedWorkspace');
357381

358382
console.log('[MOVE-SMALL] Using shared workspace with allocated libraries');
359383

@@ -433,17 +457,15 @@ export function useCalculator() {
433457
it('APP-TO-LIB: Move file from application to library', async () => {
434458
if (infrastructureFailed) return;
435459

436-
expect(sharedWorkspace).toBeDefined();
437-
if (!sharedWorkspace) return; // Type guard for TypeScript
460+
assertDefined(sharedWorkspace, 'sharedWorkspace');
438461

439462
console.log('[APP-TO-LIB] Using shared workspace with allocated library');
440463

441464
const [libName] = LIBRARY_ALLOCATION.APP_TO_LIB;
442465
const appName = sharedWorkspace.app;
443466
const workspaceName = sharedWorkspace.name;
444467

445-
expect(appName).toBeDefined();
446-
if (!appName) return;
468+
assertDefined(appName, 'appName');
447469

448470
// Add helper.ts to app with exported function
449471
const helperContent = `export function formatMessage(message: string): string {
@@ -514,8 +536,7 @@ console.log(formatMessage('Application started'));
514536
it('MOVE-PROJECT-DIR: Move with projectDirectory specified', async () => {
515537
if (infrastructureFailed) return;
516538

517-
expect(sharedWorkspace).toBeDefined();
518-
if (!sharedWorkspace) return; // Type guard for TypeScript
539+
assertDefined(sharedWorkspace, 'sharedWorkspace');
519540

520541
console.log(
521542
'[MOVE-PROJECT-DIR] Using shared workspace with allocated libraries',
@@ -583,8 +604,7 @@ console.log(formatMessage('Application started'));
583604
it('MOVE-DERIVE-DIR: Move with deriveProjectDirectory=true', async () => {
584605
if (infrastructureFailed) return;
585606

586-
expect(sharedWorkspace).toBeDefined();
587-
if (!sharedWorkspace) return; // Type guard for TypeScript
607+
assertDefined(sharedWorkspace, 'sharedWorkspace');
588608

589609
console.log(
590610
'[MOVE-DERIVE-DIR] Using shared workspace with allocated libraries',
@@ -651,8 +671,7 @@ console.log(formatMessage('Application started'));
651671
it('MOVE-SKIP-EXPORT: Move exported file with skipExport flag', async () => {
652672
if (infrastructureFailed) return;
653673

654-
expect(sharedWorkspace).toBeDefined();
655-
if (!sharedWorkspace) return; // Type guard for TypeScript
674+
assertDefined(sharedWorkspace, 'sharedWorkspace');
656675

657676
console.log(
658677
'[MOVE-SKIP-EXPORT] Using shared workspace with allocated libraries',
@@ -712,8 +731,7 @@ console.log(formatMessage('Application started'));
712731
it('MOVE-SKIP-FORMAT: Move file with skipFormat=true', async () => {
713732
if (infrastructureFailed) return;
714733

715-
expect(sharedWorkspace).toBeDefined();
716-
if (!sharedWorkspace) return; // Type guard for TypeScript
734+
assertDefined(sharedWorkspace, 'sharedWorkspace');
717735

718736
console.log(
719737
'[MOVE-SKIP-FORMAT] Using shared workspace with allocated libraries',
@@ -759,8 +777,7 @@ console.log(formatMessage('Application started'));
759777
it('MOVE-UNICODE: Move file with Unicode characters in path', async () => {
760778
if (infrastructureFailed) return;
761779

762-
expect(sharedWorkspace).toBeDefined();
763-
if (!sharedWorkspace) return; // Type guard for TypeScript
780+
assertDefined(sharedWorkspace, 'sharedWorkspace');
764781

765782
console.log(
766783
'[MOVE-UNICODE] Using shared workspace with allocated libraries',
@@ -842,8 +859,7 @@ console.log(formatMessage('Application started'));
842859
it('MOVE-REMOVE-EMPTY: Move last source files triggering project removal', async () => {
843860
if (infrastructureFailed) return;
844861

845-
expect(sharedWorkspace).toBeDefined();
846-
if (!sharedWorkspace) return; // Type guard for TypeScript
862+
assertDefined(sharedWorkspace, 'sharedWorkspace');
847863

848864
console.log(
849865
'[MOVE-REMOVE-EMPTY] Using shared workspace with allocated libraries',

0 commit comments

Comments
 (0)