Created
January 24, 2025 00:48
-
-
Save Zodiase/f357b14cc8f4d45c1da4c1f89603f211 to your computer and use it in GitHub Desktop.
Make side effects easier to clean in tests.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Use case | |
describe('some tests', () => { | |
const setEnvVar = useSideEffect((dynamicVal1: string, dynamicVal2: number) => { | |
process.env.SOME_ENV_VAR_1 = dynamicVal1; | |
process.env.SOME_ENV_VAR_2 = String(dynamicVal2); | |
return () => { | |
// Keep cleanup code close to the side-effect code. | |
delete process.env.SOME_ENV_VAR_1; | |
delete process.env.SOME_ENV_VAR_2; | |
}; | |
}); | |
afterAll(() => { | |
// A single place to clean up all side effects from `setEnvVar`. | |
setEnvVar.cleanup(); | |
}); | |
it('some test', () => { | |
setEnvVar.apply('some-value', 123); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export interface SideEffect<T extends unknown[]> { | |
/** | |
* Applies the side effect. | |
* @param args Arguments to pass to the side effect function. | |
*/ | |
apply(...args: T): void; | |
/** | |
* Cleans up the side effect from all previous apply calls. | |
*/ | |
cleanup(): void; | |
} | |
type CleanUpFn = (...args: unknown[]) => unknown; | |
/** | |
* This is helper function to create a side effect that can be easily applied and cleaned up. | |
* @param fn The function that applies the side effect when `apply` is called. It's expected to return a function to clean up for that call. | |
* @returns An object with two methods: `apply` and `cleanup`. `apply` is used to apply the side effect, and `cleanup` is used to clean up the side effect. | |
* Arguments passed to `apply` are passed to `fn`. | |
* Apply can be called multiple times, and the cleanup function will be called for each apply call. | |
*/ | |
export function useSideEffect<T extends unknown[]>(fn: (...args: T) => CleanUpFn): SideEffect<T> { | |
const cleanupFns: Array<CleanUpFn> = []; | |
return { | |
apply: (...args: T) => { | |
const cleanupFn = fn(...args); | |
// Later applies are cleaned up first. | |
cleanupFns.unshift(cleanupFn); | |
}, | |
cleanup: () => { | |
cleanupFns.forEach(cleanupFn => { | |
cleanupFn(); | |
}); | |
}, | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a rough v1 that doesn't consider async functions.