Last active
August 14, 2018 09:20
-
-
Save reneweteling/281d4911fbc5c3b373180bfe25168c7c to your computer and use it in GitHub Desktop.
Test for play application in an Lagom setup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.aceandtate.stock.api.StockService | |
import com.lightbend.lagom.scaladsl.api.{ LagomConfigComponent, ServiceAcl, ServiceInfo } | |
import com.lightbend.lagom.scaladsl.client.LagomServiceClientComponents | |
import com.lightbend.lagom.scaladsl.devmode.LagomDevModeComponents | |
import com.softwaremill.macwire._ | |
import controllers.StockController | |
import play.api.ApplicationLoader.Context | |
import play.api.libs.ws.ahc.AhcWSComponents | |
import play.api.{ ApplicationLoader, BuiltInComponentsFromContext, Mode } | |
import play.filters.HttpFiltersComponents | |
import play.api.ApplicationLoader.Context | |
import play.api.libs.ws.ahc.AhcWSComponents | |
import play.api.mvc.EssentialFilter | |
import play.api.{ ApplicationLoader, BuiltInComponentsFromContext, Mode } | |
import play.filters.HttpFiltersComponents | |
import play.i18n.I18nComponents | |
import router.Routes | |
import scala.collection.immutable | |
import scala.concurrent.ExecutionContext | |
abstract class FrontendGateway(context: Context) extends BuiltInComponentsFromContext(context) | |
with HttpFiltersComponents | |
with AhcWSComponents | |
with LagomConfigComponent | |
with LagomServiceClientComponents { | |
override lazy val serviceInfo: ServiceInfo = ServiceInfo( | |
"frontend-gateway", | |
Map( | |
"frontend-gateway" -> immutable.Seq(ServiceAcl.forPathRegex("/api/v1/.*")) | |
) | |
) | |
override implicit lazy val executionContext: ExecutionContext = actorSystem.dispatcher | |
override lazy val router = { | |
val prefix = "/api/v1" | |
wire[Routes] | |
} | |
// Services | |
lazy val stockService = serviceClient.implement[StockService] | |
// Controllers | |
lazy val stockController = wire[StockController] | |
} | |
class FrontendGatewayLoader extends ApplicationLoader { | |
override def load(context: Context) = context.environment.mode match { | |
case Mode.Dev ⇒ | |
(new FrontendGateway(context) with LagomDevModeComponents).application | |
case _ ⇒ | |
??? | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Stock management | |
GET /stock controllers.StockController.stockIndex | |
+ nocsrf | |
POST /stock controllers.StockController.createStock | |
+ nocsrf | |
PUT /stock/:stockId controllers.StockController.updateStock(stockId: String) | |
GET /stock/events controllers.StockController.stockEvents |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package controllers | |
import com.aceandtate.stock.api.{CreateStockRequest, StockService, UpdateStockRequest} | |
import play.api.data.Forms._ | |
import play.api.data.{Form, FormError} | |
import play.api.libs.json.{JsArray, JsValue, Json, Writes} | |
import play.api.mvc.{AbstractController, ControllerComponents} | |
import scala.concurrent.{ExecutionContext, Future} | |
class StockController( | |
stockService: StockService, | |
controllerComponents: ControllerComponents | |
)(implicit ec: ExecutionContext) extends AbstractController(controllerComponents) { | |
def stockIndex = Action.async { implicit req ⇒ | |
stockService | |
.getAllStock() | |
.invoke() | |
.map(x ⇒ Ok( | |
Json.toJson(x) | |
)) | |
.recoverWith { case e ⇒ Future(InternalServerError(Json.toJson(Map("cause" -> e.getLocalizedMessage)))) } | |
} | |
def createStock = Action.async { implicit req => | |
StockForm.form.bindFromRequest().fold( | |
formWithErrors => { | |
Future(Ok(JsArray(formWithErrors.errors.map(FormErrorWrites.writes)))) | |
}, | |
createStockForm => { | |
stockService | |
.createStock() | |
.invoke(CreateStockRequest(createStockForm.sku, createStockForm.initialQuantity, createStockForm.location)) | |
.map(x ⇒ Ok( | |
Json.toJson(x) | |
)) | |
.recoverWith { case e => Future(InternalServerError(Json.toJson(Map("cause" -> e.getLocalizedMessage)))) } | |
} | |
) | |
} | |
def updateStock(stockId: String) = Action.async { implicit req => | |
StockForm.form.bindFromRequest().fold( | |
formWithErrors => { | |
Future(Ok(JsArray(formWithErrors.errors.map(FormErrorWrites.writes)))) | |
}, | |
createStockForm => { | |
stockService | |
.updateStock(stockId) | |
.invoke(UpdateStockRequest(createStockForm.sku, createStockForm.initialQuantity, createStockForm.location)) | |
.map(x ⇒ Ok) | |
.recoverWith { case e => Future(InternalServerError(Json.toJson(Map("cause" -> e.getLocalizedMessage)))) } | |
} | |
) | |
} | |
def stockEvents = Action.async { implicit req => | |
stockService | |
.newStockEvents() | |
.invoke() | |
.map(x ⇒ | |
Ok.chunked( | |
x.map(s => | |
Json.toJson(s).toString + "\n" | |
) | |
) | |
) | |
.recoverWith { case e ⇒ Future(InternalServerError(Json.toJson(Map("cause" -> e.getLocalizedMessage)))) } | |
} | |
implicit object FormErrorWrites extends Writes[FormError] { | |
override def writes(o: FormError): JsValue = Json.obj( | |
"key" -> Json.toJson(o.key), | |
"message" -> Json.toJson(o.message) | |
) | |
} | |
} | |
case class StockForm(sku: String, initialQuantity: Long, location: String) | |
object StockForm { | |
val form = Form( | |
mapping( | |
"sku" -> nonEmptyText, | |
"initialQuantity" -> longNumber, | |
"location" -> nonEmptyText, | |
)(StockForm.apply)(StockForm.unapply _) | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import controllers.StockController | |
import org.scalatestplus.play.PlaySpec | |
import play.api.mvc.{Result, Results} | |
import play.api.test.FakeRequest | |
import scala.concurrent.Future | |
class StockControllerSpec extends PlaySpec with Results { | |
"Stock index" should { | |
"be valid" in { | |
// Ok.... so how do i inject, of provide the stockService and controllerComponents?? | |
val controller = new StockController(stockService, controllerComponents) | |
val result: Future[Result] = controller.stockIndex().apply(FakeRequest()) | |
val body = contentAsString(result) | |
body mustBe "ok" | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment