Testing apps that use Collect

Copy Markdown

Collect keeps document data up to date using database triggers. Because database triggers behave differently in the Ecto test sandbox, some adjustments to your test setup are required.

Use the sandbox in :auto mode

Most Ecto test suites run the SQL sandbox in :manual mode, where each test runs inside a transaction that is rolled back when the test finishes. That gives you clean isolation, but it doesn't work for testing Collect's incremental updates.

The reason is that Collect's triggers and Collect.merge_deltas/3 need to see committed data. Inside a rolled-back transaction, the data your test writes is never committed, so the triggers don't behave the way they would in production, and your assertions won't match.

So for tests that exercise document changes, switch the sandbox to :auto mode:

Ecto.Adapters.SQL.Sandbox.mode(YourApp.Repo, :auto)

This way your writes are committed, and the triggers function similar to production.

Clean up between tests

The trade-off with :auto mode is that nothing is rolled back, so anything a test creates sticks around. For Collect, that includes the triggers it installs on your tables. If one test creates a document table and the next runs without clearing it, those leftover triggers can fire during the second test and quietly throw off its results - and because it depends on test order, the failures are intermittent and hard to track down.

Clean up artifacts

Running a reset in a setup block guarantees that every test starts clean, regardless of how the previous one ended - including tests that failed partway through.

You can drop all Collect's artifacts your tests create, calling Collect.TestHelpers.reset_document_artifacts/3 for each config:

setup do
  for config <- my_test_configs() do
    Collect.TestHelpers.reset_document_artifacts(config, repo: Repo) 
  end

  :ok
end

Clean up data

Collect.TestHelpers.reset_document_artifacts/3 removes the tables and triggers Collect created, but it leaves data tables alone.

Under :auto mode, every change a test makes is committed, so you also need to reset your data between tests, or changes from one test (a deleted row, an inserted record) will carry into the next.

Reset your data with TRUNCATE ... RESTART IDENTITY CASCADE to reset the auto-incrementing identity sequence:

setup do
  Collect.TestHelpers.reset_document_artifacts(config, repo: Repo)

  Repo.query!("""
    TRUNCATE articles, categories, article_categories
    RESTART IDENTITY CASCADE
  """)
  
  # ... insert fresh fixtures
  
  :ok
end