Skip to content

Commit

Permalink
wip: lint
Browse files Browse the repository at this point in the history
  • Loading branch information
hampuslavin committed Oct 2, 2024
1 parent 218cdb2 commit 3f1d223
Showing 1 changed file with 35 additions and 11 deletions.
46 changes: 35 additions & 11 deletions docs/06-concepts/18-testing.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# Testing

Serverpod provides simple but feature rich test tools to make testing your backend a breeze.

Serverpod provides simple but feature rich test tools to make testing your backend a breeze.

## Getting started

Go to the server directory and generate the test tools by running `serverpod generate`. The default location for the generated file is `integration_test/test_tools/serverpod_test_tools.dart`.

Go to the server directory and generate the test tools by running `serverpod generate`. The default location for the generated file is `integration_test/test_tools/serverpod_test_tools.dart`.

The generated file exports a `withServerpod` helper that enables you to call your endpoints directly like regular functions:

Expand All @@ -22,8 +20,10 @@ withServerpod('Given Example endpoint', (endpoints, session) {
});
});
```

A few things to note from the above example:
- The test tools should be imported from the generated test tools file and not the `serverpod_test` package.

- The test tools should be imported from the generated test tools file and not the `serverpod_test` package.
- The `withServerpod` callback has two parameters: `endpoints` and `session`.
- `endpoints` contains all your Serverpod endpoints and lets you call them.
- `session`, just like in production code, represents the state of the world for your endpoints and is used to set up scenarios.
Expand All @@ -35,6 +35,7 @@ The location of the test tools can be changed by changing the `server_test_tool
:::

## Using `session` to set up a test scenario

The `withServerpod` helper provides a `session` object that helps with setting up different scenarios for tests. It is of type `TestSession` and has the following properties:

```dart
Expand All @@ -59,9 +60,8 @@ To create a new state, simply call `copyWith` with the new properties and use th

Below follows examples of some common scenarios.



### Setting authenticated state

```dart
withServerpod('Given AuthenticatedExample endpoint', (endpoints, session) {
// Corresponds to an actual user id
Expand Down Expand Up @@ -90,13 +90,15 @@ withServerpod('Given AuthenticatedExample endpoint', (endpoints, session) {
```

### Seeding the database
To seed the database before tests, simply pass the provided `session` to the database call exactly the same as in production code.

To seed the database before tests, simply pass the provided `session` to the database call exactly the same as in production code.

:::info

By default `withServerpod` does all database operations inside a transaction that is rolled back after each `test` case. See #TODOLINK!! for how to configure this behavior.
By default `withServerpod` does all database operations inside a transaction that is rolled back after each `test` case. See #TODOLINK!! for how to configure this behavior.

:::

```dart
withServerpod('Given Products endpoint when authenticated',
(endpoints, session) {
Expand Down Expand Up @@ -124,9 +126,11 @@ By default `withServerpod` does all database operations inside a transaction tha
```

## Environment
By default `withServerpod` uses the `test` run mode and the database settings will be read from `config/test.yaml`.

By default `withServerpod` uses the `test` run mode and the database settings will be read from `config/test.yaml`.

It is possible to override the default run mode by setting the `runMode` setting:

```dart
withServerpod(
'Given Products endpoint when authenticated',
Expand All @@ -138,7 +142,9 @@ withServerpod(
```

## Configuration

The following optional configuration options are available to pass as a second argument to `withServerpod`:

```dart
{
ResetTestSessions? resetTestSessions = ResetTestSessions.afterEach,
Expand All @@ -150,6 +156,7 @@ The following optional configuration options are available to pass as a second a
```

### `resetTestSessions`

```dart
/// Options for when to reset the test session and recreate
/// the underlying Serverpod session during the test lifecycle.
Expand All @@ -163,6 +170,7 @@ enum ResetTestSessions {
```

### `rollbackDatabase`

```dart
/// Options for when to rollback the database during the test lifecycle.
enum RollbackDatabase {
Expand All @@ -176,11 +184,13 @@ enum RollbackDatabase {
disabled,
}
```

Just like the enum describes, the behavior of the automatic rollbacks can be configured. There are two main reasons to change the default setting:

1. **Scenario tests**: when consecutive `test` cases depend on each other. This can be useful when the set up for the test group is very expensive. In this case `rollbackDatabase` can be set to `RollbackDatabase.afterAll` to ensure that the database state persists between `test` cases.

2. **Concurrent transactions in endpoints**: when concurrent calls are made to `session.db.transaction` inside an endpoint, it is no longer possible for the Serverpod test tools to do these operations as part of a top level transaction.

```dart
Future<void> concurrentTransactionCalls(
Session session,
Expand Down Expand Up @@ -220,34 +230,43 @@ withServerpod(
```

### `runMode`

The run mode that Serverpod should be running in. Defaults to `test`.

### `enableSessionLogging`

Wether session logging should be enabled. Defaults to `false`.

### `applyMigrations`

Wether pending migrations should be applied when starting Serverpod. Defaults to `true`.

## DOs and DONTs

### Imports

**Don't**

Check failure on line 248 in docs/06-concepts/18-testing.md

View workflow job for this annotation

GitHub Actions / markdown-lint

Emphasis used instead of a heading [Context: "Don't"]

```dart
import 'serverpod_test_tools.dart';
// Don't import `serverpod_test` directly.
import 'package:serverpod_test/serverpod_test.dart'; ❌
```

**Do**

Check failure on line 256 in docs/06-concepts/18-testing.md

View workflow job for this annotation

GitHub Actions / markdown-lint

Emphasis used instead of a heading [Context: "Do"]

```dart
// Only import the generated test tools file.
// It re-exports all helpers and types that are needed.
import 'serverpod_test_tools.dart'; ✅
```

### Database clean up

Unless configured otherwise, by default `withServerpod` does all database operations inside a transaction that is rolled back after each `test`.

**Don't**

Check failure on line 268 in docs/06-concepts/18-testing.md

View workflow job for this annotation

GitHub Actions / markdown-lint

Emphasis used instead of a heading [Context: "Don't"]

```dart
withServerpod('Given ProductsEndpoint', (endpoints, session) {
setUp(() async {
Expand All @@ -264,7 +283,9 @@ withServerpod('Given ProductsEndpoint', (endpoints, session) {
// ...
});
```

**Do**

Check failure on line 287 in docs/06-concepts/18-testing.md

View workflow job for this annotation

GitHub Actions / markdown-lint

Emphasis used instead of a heading [Context: "Do"]

```dart
withServerpod('Given ProductsEndpoint', (endpoints, session) {
setUp(() async {
Expand All @@ -279,13 +300,14 @@ withServerpod('Given ProductsEndpoint', (endpoints, session) {

### Session clean up


## Advanced examples

### Multiple users interacting with a shared stream

For cases where there are multiple users reading from or writing to a stream, such as real-time communication, it can be helpful to validate this behavior in tests.

Given the following simplified endpoint:

```dart
class CommunicationExampleEndpoint {
static const sharedStreamName = 'shared-stream';
Expand All @@ -304,7 +326,9 @@ class CommunicationExampleEndpoint {
}
}
```

Then a test to verify this behavior can be written as below. Note the call to the `flushMicrotasks` helper (exported by the test tools), which ensures that `listenForNumbersOnSharedStream` executes up to its first `yield` statement before continuing with the test. This guarantees that the stream was registered by Serverpod before messages are posted to it.

```dart
withServerpod('Given CommunicationExampleEndpoint', (endpoints, session) {
const int userId1 = 1;
Expand Down

0 comments on commit 3f1d223

Please sign in to comment.