Environment variables
Loading "Environment Variables"
Run locally for transcripts
Another kind of global dependency your code may have is on the environment. This is often done via environment variables, which, in JavaScript, are often exposed to the process via the
process.env
object.You use environment variables for tasks like managing API secrets, feature flags, or implementing environment-specific logic. Consequently, environment variables are another dependency you need to know how to mock to properly orchestrate your tests.
One of the most common usages of environment variables is the dependency on the current process' environment, i.e.
process.env.NODE_ENV
. That's precisely what our Emitter
class does to imbue its methods with logging capabilities if run in development:function isDevelopment() {
return process.env.NODE_ENV === 'development'
}
export class Emitter<EventMap extends Record<string, Array<unknown>>> {
// ...
public on<Event extends keyof EventMap>(
event: Event,
listener: (...args: EventMap[Event]) => void,
): this {
if (isDevelopment()) {
console.log(`adding listener for "${event.toString()}" event`)
}
const prevListeners = this.listeners.get(event) || []
const nextListeners = prevListeners.concat(listener)
this.listeners.set(event, nextListeners)
return this
}
public emit<Event extends keyof EventMap>(
event: Event,
...data: EventMap[Event]
): boolean {
const listeners = this.listeners.get(event) || []
if (isDevelopment()) {
console.log(
`emitting listeners for "${event.toString()}" event (${
listeners.length
})`,
)
}
for (const listener of listeners) {
listener.apply(this, data)
}
return listeners.length > 0
}
}
First, it determines the environment on runtime via the
isDevelopment()
function, and then implements additional logic in the .on()
and .emit()
methods of the Emitter
based on result of the isDevelopment()
function call.But how do you test this?
You can, of course, set a different
NODE_ENV
environment variable when running the test script itself:NODE_ENV=development npm test
But this won't play nicely on different operating systems, and will affect the entire test run instead of focusing on a single test suite. The worst part is that you wonβt be able to change the
NODE_ENV
value only for specific test cases to see how your code behaves.Alternatively, you can mock
process.env.NODE_ENV
as a global value, like you did in the previous exercise. That would work, but you would have to remember to forward all existing environment variables on process.env
before mocking your own variables. This can easily be forgotten, leading to unreliable or even broken tests.You can use
vi.stubEnv()
!π¨βπΌ The time has come for you to get to know
vi.stubEnv()
. In this exercise, add new test cases for the test suite by mocking the value of process.env.NODE_ENV
using the built-in Vitest vi.stubEnv()
API. Verify your solution by running npm test
. And remember, you will be asserting on console.log
calls too!