TLDR : Here is a minimally reproduceable example. You do not need a Supabase account / database to get the error.
I have some code like this, which performs some simple transformation of data before saving it in Supabase
suspend fun saveClones(owner: String, repository: String, clones: GitHubClones): List<ResultClone> {
val zeClones = clones.clones.map {
Clone(
owner = owner,
repository = repository,
count = it.count,
uniques = it.uniques,
timestamp = it.timestamp
)
}
return client.postgrest["clone"].insert(zeClones, upsert = true, onConflict = "owner, repository, timestamp").decodeList<ResultClone>()
}
I'd like to check that the data going in the insert call is what I expect it to be. I've tried to mock the client using mockk as such
val supabaseClient = mockk<SupabaseClient>()
val postgrest = mockk<Postgrest>()
val postgrestBuilder = mockk<PostgrestBuilder>()
val postgrestResult = PostgrestResult(body = null, headers = Headers.Empty)
every { supabaseClient.postgrest } returns postgrest
every { postgrest["path"] } returns postgrestBuilder
coEvery { postgrestBuilder.insert(values = any<List<Path>>()) } returns postgrestResult
but when running my test, I am facing the following error :
java.lang.IllegalStateException: Plugin rest not installed or not of type Postgrest. Consider installing Postgrest within your supabase client builder
at io.github.jan.supabase.postgrest.PostgrestKt.getPostgrest(Postgrest.kt:172)
at nl.lengrand.GitHubTrafficStoreTest$setUp$1.invoke(GitHubTrafficStoreTest.kt:53)
at nl.lengrand.GitHubTrafficStoreTest$setUp$1.invoke(GitHubTrafficStoreTest.kt:53)
What would be the correct way to unit test that function? It looks like I also cannot really use test containers with Supabase, making integration tests equally as difficult.
Coming back here just to mentioned that I decided to go another direction, which I'm pretty satisfied with actually. I created a simple Docker Compose setup that I run with test containers and which simulate a simple Supabase instance. No need for mocking any more. It's more "integration tests" than "unit tests" at that point though.
The full blog about it, but in short :
version: '3'
# Thanks https://github.com/mattddowney/compose-postgrest/blob/master/README.md
services:
################
# postgrest-db #
################
postgrest-db:
image: postgres:16-alpine
ports:
- "5432:5432"
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
- DB_SCHEMA=${DB_SCHEMA}
volumes:
- "./initdb:/docker-entrypoint-initdb.d"
networks:
- postgrest-backend
restart: always
#############
# postgrest #
#############
postgrest:
image: postgrest/postgrest:latest
ports:
- "3000:3000"
environment:
- PGRST_DB_URI=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgrest-db:5432/${POSTGRES_DB}
- PGRST_DB_SCHEMA=${DB_SCHEMA}
- PGRST_DB_ANON_ROLE=${DB_ANON_ROLE}
- PGRST_JWT_SECRET=${PGRST_JWT_SECRET}
networks:
- postgrest-backend
restart: always
#############
# Nginx #
#############
nginx:
image: nginx:alpine
restart: always
tty: true
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- "80:80"
- "443:443"
networks:
- postgrest-backend
networks:
postgrest-backend:
driver: bridge
and the test file :
import io.github.jan.supabase.SupabaseClient
import io.github.jan.supabase.createSupabaseClient
import io.github.jan.supabase.postgrest.Postgrest
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.testcontainers.containers.ComposeContainer
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers
import java.io.File
@Testcontainers
class MainKtTestTestContainers {
// The jwt token is calculated manually (https://jwt.io/) based on the private key in the docker-compose.yml file, and a payload of {"role":"postgres"} to match the user in the database
private val jwtToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXMifQ.88jCdmcEuy2McbdwKPmuazNRD-dyD65WYeKIONDXlxg"
private lateinit var supabaseClient: SupabaseClient
@Container
var environment: ComposeContainer =
ComposeContainer(File("src/test/resources/docker-compose.yml"))
.withExposedService("postgrest-db", 5432)
.withExposedService("postgrest", 3000)
.withExposedService("nginx", 80)
@BeforeEach
fun setUp() {
val fakeSupabaseUrl = environment.getServiceHost("nginx", 80) +
":" + environment.getServicePort("nginx", 80)
supabaseClient = createSupabaseClient(
supabaseUrl = "http://$fakeSupabaseUrl",
supabaseKey = jwtToken
) {
install(Postgrest)
}
}
@Test
fun testEmptyPersonTable(){
runBlocking {
val result = getPerson(supabaseClient)
assertEquals(0, result.size)
}
}
@Test
fun testSavePersonAndRetrieve(){
val randomPersons = listOf(Person("Jan", 30), Person("Jane", 42))
runBlocking {
val result = savePerson(randomPersons, supabaseClient)
assertEquals(2, result.size)
assertEquals(randomPersons, result.map { it.toPerson() })
val fetchResult = getPerson(supabaseClient)
assertEquals(2, fetchResult.size)
assertEquals(randomPersons, fetchResult.map { it.toPerson() })
}
}
}