cashapp / paparazzi

Render your Android screens without a physical device or emulator
https://cashapp.github.io/paparazzi/
Apache License 2.0
2.31k stars 215 forks source link

Decouple Paparazzi from JUnit 4 (TestRule) #282

Open TWiStErRob opened 3 years ago

TWiStErRob commented 3 years ago

I'll add an example what this means, how JUnit 5 extensions work.

TWiStErRob commented 3 years ago

See https://github.com/cashapp/paparazzi/pull/293

kirillzh commented 1 year ago

+1 for this request, would love to see paparazzi get decoupled from Junit 4 test rule. In our use case, we are using Kotest framework, and from what I have found so far, there's no official Kotest integration for Junit 4 test rules. The solution that I came up with is to implement custom Kotest extension that mimics what Paparazzi rule logic does, looks like this:

import app.cash.paparazzi.Paparazzi
import io.kotest.core.TestConfiguration
import io.kotest.core.listeners.AfterTestListener
import io.kotest.core.listeners.BeforeTestListener
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import org.junit.runner.Description
import org.junit.runners.model.Statement

class PaparazziExtension(
 val paparazzi: Paparazzi,
) : BeforeTestListener, AfterTestListener {

  override suspend fun beforeTest(testCase: TestCase) {
    val junit4Description = testCase.junit4Description
    paparazzi.apply(
      base = NoopJunitStatement,
      description = junit4Description,
    )
    paparazzi.prepare(junit4Description)
  }

  override suspend fun afterTest(testCase: TestCase, result: TestResult) {
    paparazzi.close()
  }
}

private object NoopJunitStatement : Statement() {
  override fun evaluate() = Unit
}

private val TestCase.junit4Description: Description
  get() = Description.createTestDescription(descriptor.parent.id.value, name.testName)

Kotest usage looks like this:

import app.cash.paparazzi.DeviceConfig.Companion.PIXEL_6
import build.wallet.kotest.paparazzi.paparazziExtension
import io.kotest.core.spec.style.FunSpec

class ButtonSnapshots : FunSpec({
  val paparazzi = Paparazzi(deviceConfig = PIXEL_6)
  extension(PaparazziExtension(paparazzi))

  test("button - primary treatment, compact size, enabled, no icon") {
    paparazzi.snapshot {
      // ... theme wrapping
      Button(
        treatment = ButtonTreatment.Primary,
        size = ButtonSize.Compact
      )
    }
  }
})
anhanh11001 commented 1 year ago

+1 for this request.

@TWiStErRob Can I also ask if there are estimated timeline for this + Milestone 1.2 (seems like end of 2022, but not sure if this is correct)?