avajs / ava

Node.js test runner that lets you develop with confidence 🚀
MIT License
20.74k stars 1.41k forks source link

before and after global hooks? Concurrently testing a shared state #311

Closed mattkrick closed 8 years ago

mattkrick commented 8 years ago

As I understand it, before and after are file-specific, meaning when the last test in that file completes, the after hook is called.

I'm doing some database testing & I have multiple test files. When all the tests complete, I'd like to drop the table. The problem is, I'm not sure which file will complete last. If I drop the table at the end of the file A, it'll screw up tests currently running in file B, so I can't put a hook in every file.

Currently, i put those hooks in my largest test file and hope for the best. I could create a new DB for each test file, but that seems kinda crazy. I could also set the global serial flag, but that kills the performance boost.

Is there a better way for concurrently testing things that share state? Or alternatively maybe have tests run concurrently, but files in serial?

BarryThePenguin commented 8 years ago

Can you create your table before you run AVA and clean up after running AVA? This sounds like something more suited to a task runner

mattkrick commented 8 years ago

That's a good suggestion. Until now I've been able to do without one (just webpack + npm) but I guess that's the best choice. Thanks!

BarryThePenguin commented 8 years ago

npm has pre and post scripts https://docs.npmjs.com/misc/scripts

pretest and posttest should be helpful

mattkrick commented 8 years ago

I totally forgot those existed! Oh that's awesome, cheers!

scottmas commented 6 years ago

@mattkrick It would be awesome if this could be re-opened. The biggest thing is if we want to have mandatory initialization and cleanup scripts running before the tests. It's a HUGE pain.

To get a before global initialization hook (with async http requests, etc), I can do so with a --require init-script.js ava and then inside that script do a gross child_process.spawnSync to delay execution of Ava until the http requests inside the script completely finish.

And then, to get a global post execution hook, I have to some gross Bash hackery to get the exist code and the test output. I'm not proud to commit into my code base:

TEMP_OUTPUT=$(ava ./server/e2e/**/*.e2e.js --timeout 300000 2>&1); \
export TEST_EXIT_CODE=$?; export TEST_OUTPUT=$TEMP_OUTPUT; \
node post-script.js && exit $TEST_EXIT_CODE
novemberborn commented 6 years ago

@scottmas it's pretty much impossible for AVA to synchronize before/after function hooks in their current form, hence our advocating of pretest and posttest scripts. #1366 has an intriguing suggestion for managing resources during an AVA invocation. Somebody would have to flesh out a proposal on quite how that would work, but I'd be open to that.

scottmas commented 6 years ago

A function hook isn't strictly necessary. What about a global before and after script file invocations? Like the existing --require option but actually waiting for the file execution to complete before continuing on. E.g. I can imagine my Ava config looking like so:

{
  "ava": {
    "globalHooks": {
        "before": "./e2e-setup.js",
        "after" : "./e2e-cleanup.js",
        "force": ["after"]
    }
  }
}

The resource approach outlined does looks amazing, but I can imagine this being way simpler to implement. What do you think?

novemberborn commented 6 years ago

I don't think that provides enough value over wrapping AVA's invocation in a shell script, however messy that shell script may be.

Retsam commented 3 years ago

It makes sense that AVA can't provide this sort of hook; but I'm having a bit of trouble adapting this to my use case. I'm trying to run a process (s3rver - a local S3 mock) while running tests.

I can start and background the process in a "pretest" hook, but I can't seem to find a reliable way to kill the process in a "posttest" hook.

novemberborn commented 3 years ago

I run tests with Firestore and Pub/Sub emulators, and those I start separately. Not perfect but gets the job done. Same in CI: launch them as the job starts.

https://github.com/avajs/ava/pull/2478 provides a foundation for letting you hook into AVA itself, to manage resources around test runs. I haven't yet had the time to document that and to sketch it out further so it's more accessible for contributors.