Introduction to Testing with Remult

Remult makes it simple to replace your production database with a test database, enabling you to easily write and execute automated tests. The flexibility of switching between databases allows you to verify logic, validations, and even SQL-related functionality in your entities, streamlining the testing process for development.

Code Example: Basic Validation Tests

The example below sets up tests for the Task entity to check basic validation logic:

tests/validations.test.ts
5 collapsed lines
import { describe, test, expect, beforeEach } from 'vitest'
import { remult, repo, InMemoryDataProvider, SqlDatabase } from 'remult'
import { createSqlite3DataProvider } from 'remult/remult-sqlite3'
import { Task } from '../shared/Task'
describe('Test validations', () => {
beforeEach(async () => {
remult.dataProvider = new InMemoryDataProvider()
})
10 collapsed lines
test('Task with title', async () => {
await repo(Task).insert({ title: 'Task 1' })
expect(await repo(Task).count()).toBe(1)
})
test('Task without title', async () => {
await expect(() => repo(Task).insert({})).rejects.toThrowError(
'Title: Should not be empty',
)
})
})

Code Explanation

  1. Setting the Data Provider for Tests:

    • Inside the beforeEach hook, the test database is set to InMemoryDataProvider, allowing for fast, transient data access without needing a real database connection.
  2. Test Cases:

    • Task with Title: This test creates a task with a title and verifies that the task count increases by one.
    • Task without Title: This test attempts to insert a task without a title, triggering a validation error. The expect(error.message) statement then verifies the validation message.

Try It Out

Click the Toggle Terminal button on the right to see the test execution and validation output.


Testing SQL-Based Logic

For testing SQL expressions or SQL-based filters, use an in-memory SQLite database, which supports SQL functionality without needing a production database connection.

tests/validations.test.ts
6 collapsed lines
import { describe, test, expect, beforeEach } from 'vitest'
import { remult, repo, InMemoryDataProvider, SqlDatabase } from 'remult'
import { createSqlite3DataProvider } from 'remult/remult-sqlite3'
import { Task } from '../shared/Task'
describe('Test validations', () => {
beforeEach(async () => {
remult.dataProvider = await createSqlite3DataProvider()
// makes sure the table exists in the database
await remult.dataProvider.ensureSchema?.([repo(Task).metadata])
// SqlDatabase.LogToConsole = true
})
10 collapsed lines
test('Task with title', async () => {
await repo(Task).insert({ title: 'Task 1' })
expect(await repo(Task).count()).toBe(1)
})
test('Task without title', async () => {
await expect(() => repo(Task).insert({})).rejects.toThrowError(
'Title: Should not be empty',
)
})
})

Explanation of SQL Test Setup

  • createSqlite3DataProvider: Sets an SQLite database in memory, enabling tests for SQL-related code.
  • ensureSchema: This ensures that the table structure matches your entity metadata, automatically creating tables as needed.
  • SqlDatabase.LogToConsole: Setting this to true outputs SQL statements to the console, helping verify that SQL operations are working as expected.

Using Your Actual Database Provider

In addition to in-memory testing, you can test with your actual database provider by setting it to remult.dataProvider, ensuring compatibility and performance for production scenarios.


By using these techniques, you can write comprehensive tests covering all entity aspects, from validations to SQL expressions.

Powered by WebContainers
Files
Preparing Environment
  • Installing dependencies
  • Starting http server