-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce htmx tests with Playwright
Co-authored-by: Stéphane Épardaud <[email protected]>
- Loading branch information
Showing
19 changed files
with
403 additions
and
10 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
:quarkus-version: 3.6.4 | ||
:quarkus-version: 3.6.5 | ||
:quarkus-renarde-version: 3.0.7 | ||
:maven-version: 3.8.1+ | ||
|
||
|
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package rest; | ||
|
||
import java.util.Collection; | ||
|
||
import jakarta.inject.Inject; | ||
import jakarta.validation.constraints.Email; | ||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.Pattern; | ||
import jakarta.ws.rs.DELETE; | ||
import jakarta.ws.rs.PUT; | ||
import jakarta.ws.rs.Path; | ||
|
||
import org.jboss.resteasy.reactive.RestForm; | ||
import org.jboss.resteasy.reactive.RestPath; | ||
|
||
import io.quarkiverse.renarde.htmx.HxController; | ||
import io.quarkus.qute.CheckedTemplate; | ||
import io.quarkus.qute.TemplateInstance; | ||
import service.ContactService; | ||
|
||
public class HtmxApp extends HxController { | ||
|
||
@Inject | ||
ContactService contactService; | ||
|
||
@CheckedTemplate | ||
static class Templates { | ||
|
||
public static native TemplateInstance index(Collection<ContactService.Contact> contacts); | ||
|
||
public static native TemplateInstance index$list(Collection<ContactService.Contact> contacts); | ||
|
||
} | ||
|
||
@CheckedTemplate(basePath = "HtmxApp/partials") | ||
static class Partials { | ||
|
||
public static native TemplateInstance view(ContactService.Contact contact); | ||
|
||
public static native TemplateInstance edit(ContactService.Contact contact); | ||
|
||
} | ||
|
||
@Path("") | ||
public TemplateInstance index() { | ||
if (isHxRequest()) { | ||
return Templates.index$list(contactService.contacts().values()); | ||
} | ||
return Templates.index(contactService.contacts().values()); | ||
} | ||
|
||
public TemplateInstance view(@RestPath int id) { | ||
if (!contactService.contacts().containsKey(id)) { | ||
throw new IllegalArgumentException("Invalid id: " + id); | ||
} | ||
return Partials.view(contactService.contacts().get(id)); | ||
} | ||
|
||
public TemplateInstance edit(@RestPath int id) { | ||
if (!contactService.contacts().containsKey(id)) { | ||
throw new IllegalArgumentException("Invalid id: " + id); | ||
} | ||
return Partials.edit(contactService.contacts().get(id)); | ||
} | ||
|
||
@PUT | ||
public void save(@RestPath int id, @RestForm @NotBlank @Pattern(regexp = "[A-Z][a-z]+") String firstName, | ||
@RestForm @NotBlank @Pattern(regexp = "[A-Z]+") String lastName, | ||
@RestForm @Email String email) { | ||
if (!contactService.contacts().containsKey(id)) { | ||
throw new IllegalArgumentException("Invalid id: " + id); | ||
} | ||
|
||
if (validationFailed()) { | ||
edit(id); | ||
} | ||
|
||
final ContactService.Contact contact = contactService.contacts().get(id); | ||
contact.firstName = firstName; | ||
contact.lastName = lastName; | ||
contact.email = email; | ||
view(id); | ||
} | ||
|
||
@PUT | ||
public void lock(@RestPath int id) { | ||
if (!contactService.contacts().containsKey(id)) { | ||
throw new IllegalArgumentException("Invalid id: " + id); | ||
} | ||
final ContactService.Contact contact = contactService.contacts().get(id); | ||
contact.locked = !contact.locked; | ||
if (contact.locked) { | ||
view(id); | ||
} else { | ||
edit(id); | ||
} | ||
} | ||
|
||
@DELETE | ||
public void delete(@RestPath int id) { | ||
if (!contactService.contacts().containsKey(id)) { | ||
throw new IllegalArgumentException("Invalid id: " + id); | ||
} | ||
contactService.contacts().remove(id); | ||
hx(HxResponseHeader.TRIGGER, "refreshList"); | ||
} | ||
|
||
} |
51 changes: 51 additions & 0 deletions
51
integration-tests/src/main/java/service/ContactService.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package service; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import jakarta.enterprise.context.ApplicationScoped; | ||
|
||
@ApplicationScoped | ||
public class ContactService { | ||
private static final Contact JOE = new Contact(6, "Joe", "BLOW", "[email protected]"); | ||
private static final Contact FOO = new Contact(7, "Foo", "BLOW", "[email protected]"); | ||
private static final Contact BAR = new Contact(10, "Bar", "AWESOME", "[email protected]"); | ||
|
||
private final Map<Integer, Contact> contacts = new HashMap<>(); | ||
|
||
public ContactService() { | ||
reset(); | ||
} | ||
|
||
public Map<Integer, Contact> contacts() { | ||
return contacts; | ||
} | ||
|
||
public void reset() { | ||
contacts.clear(); | ||
contacts.put(JOE.id, JOE.clone()); | ||
contacts.put(FOO.id, FOO.clone()); | ||
contacts.put(BAR.id, BAR.clone()); | ||
} | ||
|
||
public static class Contact { | ||
public final int id; | ||
public String firstName; | ||
public String lastName; | ||
public String email; | ||
|
||
public boolean locked = false; | ||
|
||
public Contact(int id, String firstName, String lastName, String email) { | ||
this.id = id; | ||
this.firstName = firstName; | ||
this.lastName = lastName; | ||
this.email = email; | ||
} | ||
|
||
@Override | ||
public Contact clone() { | ||
return new Contact(id, firstName, lastName, email); | ||
} | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
integration-tests/src/main/resources/META-INF/resources/htmx.js
Large diffs are not rendered by default.
Oops, something went wrong.
2 changes: 2 additions & 0 deletions
2
integration-tests/src/main/resources/templates/Application/gravatar.html
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
{#gravatar "[email protected]" size="200" alt="Gravatar" class="foo bar" aria-label="my gravatar" /} | ||
{#gravatar "[email protected]" /} |
32 changes: 32 additions & 0 deletions
32
integration-tests/src/main/resources/templates/HtmxApp/index.html
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | ||
<title>Htmx Powered</title> | ||
<link rel="icon" href="/favicon.ico" type="image/x-icon"> | ||
<script src="/htmx.js"></script> | ||
<link rel="stylesheet" media="screen" href="/webjars/bootstrap/css/bootstrap.min.css"> | ||
<style> | ||
input:read-only { | ||
background-color: #e9ecef; | ||
} | ||
</style> | ||
</head> | ||
<body hx-headers='{"{inject:csrf.headerName}":"{inject:csrf.token}"}'> | ||
<main class="container"> | ||
|
||
<h1>Htmx Powered</h1> | ||
<div hx-get="{uri:HtmxApp.index}" hx-trigger="refreshList from:body"> | ||
{#fragment id="list"} | ||
{#for contact in contacts} | ||
<div class="row mb-4"> | ||
{#include HtmxApp/partials/view /} | ||
</div> | ||
{/for} | ||
{/fragment} | ||
</div> | ||
</main> | ||
</body> | ||
</html> |
23 changes: 23 additions & 0 deletions
23
integration-tests/src/main/resources/templates/HtmxApp/partials/edit.html
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<div class="col" hx-target='this' hx-swap="outerHTML" aria-label="Editing {contact.firstName} {contact.lastName}"> | ||
{#form hx-put=uri:HtmxApp.save(contact.id) style="display: contents;"} | ||
{#formElement name="firstName" label="First Name"} | ||
{#input name="firstName" value=contact.firstName readonly=contact.locked/} | ||
{/formElement} | ||
{#formElement name="lastName" label="Last Name"} | ||
{#input name="lastName" value=contact.lastName readonly=contact.locked/} | ||
{/formElement} | ||
{#formElement name="email" label="Email Address"} | ||
{#input name="email" type="email" value=contact.email readonly=contact.locked/} | ||
{/formElement} | ||
|
||
{#if !contact.locked} | ||
<button class="btn btn-primary" aria-label="Save">Save</button> | ||
{/if} | ||
<button class="btn btn-warning" hx-get="{uri:HtmxApp.view(contact.id)}" aria-label="Cancel">Cancel</button> | ||
{/form} | ||
{#if !contact.locked} | ||
<button class="btn btn-danger" hx-delete="{uri:HtmxApp.delete(contact.id)}" aria-label="Delete">Delete</button> | ||
{/if} | ||
<button class="btn btn-secondary" hx-put="{uri:HtmxApp.lock(contact.id)}" aria-label="{contact.locked ? 'Unlock' : 'Lock'}">{contact.locked ? 'Unlock' : 'Lock'}</button> | ||
|
||
</div> |
10 changes: 10 additions & 0 deletions
10
integration-tests/src/main/resources/templates/HtmxApp/partials/view.html
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<div class="col" hx-target="this" hx-swap="outerHTML" aria-label="Viewing {contact.firstName} {contact.lastName}"> | ||
<div aria-label="Details"> | ||
<div><label>First Name</label>: {contact.firstName}</div> | ||
<div><label>Last Name</label>: {contact.lastName}</div> | ||
<div><label>Email</label>: {contact.email}</div> | ||
</div> | ||
<button hx-get="{uri:HtmxApp.edit(contact.id)}" class="btn btn-primary" aria-label="Edit"> | ||
Click To Edit | ||
</button> | ||
</div> |
7 changes: 7 additions & 0 deletions
7
integration-tests/src/main/resources/templates/tags/formElement.html
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<div class="mb-3 form-group"> | ||
<label class="form-label" for="{name}">{label}</label> | ||
{nested-content} | ||
{#ifError name} | ||
<span class="invalid-feedback" aria-label="Error for {name}">{#error name/}</span> | ||
{/ifError} | ||
</div> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<input type="{type ?: 'text'}" class="{class ?: 'form-control'} {#ifError name}is-invalid{/ifError}" {#if readonly}readonly ‹{/if}value="{inject:flash.get(name) ?: value}" {_args.skip('class', 'type', 'readonly').asHtmlAttributes.safe}/> |
Oops, something went wrong.