Environment variables

Another kind of global dependency your code may have is that on the environment. That is often done via environment variables, which, in JavaScript, are often exposed to the process via the process.env object.
You reach out to environment variables in cases like managing API secrets, feature flags, implementing different environment-depending logic, etc. And as such, dependency on environment variable is also one you have to know how to mock to orchestrate your tests correctly.
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 on 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, you won't be able to swap the value of NODE_ENV only in some 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 not to forget to forward all the existing environment variables on process.env before mocking your own variable or two. This can easily slip past your mind, resulting in unreliable and, at times, broken tests.
You can also use vi.stubEnv()!
πŸ‘¨β€πŸ’Ό The time has come for you to get to know vi.stubEnv(). In this exercise, complete new test cases for the test suite by mocking the value of process.env.NODE_ENV using the built-in vi.stubEnv() API in Vitest. Verify your solution by running npm test. And remember, you will be asserting on console.log calls too!

Access Denied

You must login or register for the workshop to view the diff.

Check out this video to see how the diff tab works.