Skip to content

Commit

Permalink
fix: inject isolation fixtures into test fixtures
Browse files Browse the repository at this point in the history
  • Loading branch information
skellet0r committed Apr 17, 2022
1 parent eedcd5f commit 98da061
Showing 1 changed file with 27 additions and 20 deletions.
47 changes: 27 additions & 20 deletions src/ape/pytest/runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,32 +82,39 @@ def pytest_exception_interact(self, report, call):
if capman:
capman.resume_global_capture()

@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(self, item):
def pytest_runtest_setup(self, item):
"""
By default, snapshot the chain before each test case is ran and restore the chain state
right after. This is done as close as possible to test execution, after fixtures have been
setup and before fixture teardown.
By default insert isolation fixtures into each test cases list of fixtures
prior to actually executing the test case.
https://docs.pytest.org/en/6.2.x/reference.html#pytest.hookspec.pytest_runtest_call
https://docs.pytest.org/en/6.2.x/reference.html#pytest.hookspec.pytest_runtest_setup
"""
if self.pytest_config.getoption("disable_isolation") is True:
# default isolation is disabled
yield
else:
snapshot_id = None

# Try to snapshot if the provider supported it.
try:
snapshot_id = self.chain_manager.snapshot()
except NotImplementedError:
self._warn_for_unimplemented_snapshot()
# isolation is disabled via cmdline option
return

yield
# list of scopes for each fixture of the test
scopes = [item._fixtureinfo.name2fixturedefs[f][0].scope for f in item.fixturenames]

# Try to revert to the state before the test began.
if snapshot_id is not None:
self.chain_manager.restore(snapshot_id)
idx = 0
for scope in ["session", "package", "module", "class"]:
# iterate through scope levels and insert the isolation fixture
# prior to the first fixture with that scope
try:
idx = scopes.index(scope, idx)
except ValueError:
# intermediate scope isolations are filled in by later fixtures
# even if they are skipped (which will only happen if no fixture
# is defined at that scope level)
continue
item.fixturenames.insert(idx, f"_{scope}_isolation")
scopes.insert(idx, scope)

# lastly insert function isolation
try:
item.fixturenames.insert(scopes.index("function", idx), "_function_isolation")
except ValueError:
item.fixturenames.append("_function_isolation")

def _warn_for_unimplemented_snapshot(self):
if self._warned_for_missing_features:
Expand Down

0 comments on commit 98da061

Please sign in to comment.