Selenium/Ruby/Environment abstraction layer

Project Overview
The Environment Abstraction Layer component of the mediawiki_selenium framework was started as part of a effort to: 1) abstract environment-specific resource dependencies to reduce coupling and improve test determinism; 2) provide a DSL for common MediaWiki-related test patterns; 3) better isolate test implementation that requires multiple sessions; and 4) allow for custom configuration of browser settings such as language, proxies, etc. without having to add support to the core framework.

Environment Configuration
We face limitations in the "given" steps of test implementation when it comes to setting up initial application state. Lacking the database access required for test fixtures we must, instead, rely on other methods of resource provisioning such as the MW API or Selenium-driven configuration via the UI. For resources that cannot be setup using either method—such as instances of wikis themselves and additional users (on account of CAPTCHA)—we rely on environmental configuration.

Configuration is currently accomplished using a simple set of environment variables that are referenced in code using Ruby's  global. This is sufficient for most use cases, but there are a few problems to the approach that the EAL solves.

Variable Lookup
First, the  global is a simple   that provides no guarantee or expectation of failure when a requested variable is not found. A developer can implement their own checks, but that must be done for each and every case, and many times leads to redundant nil/empty string checks.

If a strict check for the configuration is not enforced, it typically leads to unexpected/obscure failure down the line.

The EAL solves both of these problems by enforcing a uniformly strict policy on variable lookup unless a default value is explicitly provided.

Global State
Mutation of the global  object is permitted by Ruby, but it's generally not a good idea as it can lead to race conditions and other unpredictable behavior, especially in evented contexts such as Cucumber's.

To illustrate the complications, consider how we (for security reasons) configure the test-user's password in CI by way of a alternative variable (corresponding to ).

Now imagine this same global variable is referenced somewhere else, say in another  hook that's defined somewhere in the project's test-suite.

It's entirely possible, depending on how the various support files were imported, that this second hook would end up executing before the first, an example of a simple race condition.

The EAL prevents these conditions by providing a one-way, read-only path for environment configuration; configuration variables may be read by test implementation but never defined.

Additional to preventing mutation of its state, the  object provides methods for accessing things like the test-user's password that may come from different sources or require logic to fully construct.