Compare commits
3
Commits
4adcfb1377
...
279cdb869d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
279cdb869d | ||
|
|
fbb49bc560 | ||
|
|
7309971c74 |
@@ -6,3 +6,4 @@
|
||||
/e2e/node_modules/
|
||||
/e2e/test-results/
|
||||
/e2e/playwright-report/
|
||||
/test-results/
|
||||
|
||||
@@ -48,7 +48,7 @@ test("the add-meal picker closes when clicking outside", async ({ page }) => {
|
||||
const picker = page.locator(".meal-picker-backdrop");
|
||||
await expect(picker).toBeVisible();
|
||||
|
||||
// Click the backdrop itself (outside the modal card).
|
||||
await picker.click({ position: { x: 5, y: 5 } });
|
||||
// Click the backdrop itself (outside the modal card), at the viewport corner.
|
||||
await page.mouse.click(10, 10);
|
||||
await expect(picker).toHaveCount(0);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { expect } from "@playwright/test";
|
||||
import { test } from "../fixtures";
|
||||
import { registerAndLogin, createList, addItem } from "../helpers";
|
||||
|
||||
test("a list updates live for another user via websocket", async ({ page, browser, server }) => {
|
||||
// User A registers and creates a list.
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
await createList(page, "Weekly shop");
|
||||
const listUrl = page.url();
|
||||
|
||||
// User B registers in a separate context (separate session).
|
||||
const contextB = await browser.newContext({ baseURL: server.baseURL });
|
||||
const pageB = await contextB.newPage();
|
||||
await registerAndLogin(pageB, "bob@example.com");
|
||||
|
||||
// Both users open the same list.
|
||||
await page.goto(listUrl);
|
||||
await pageB.goto(listUrl);
|
||||
|
||||
// Give the websocket connections a moment to establish.
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// User A adds an item.
|
||||
await addItem(page, "Apple", "2");
|
||||
|
||||
// It should appear on User B's page without any reload.
|
||||
await expect(pageB.locator(".item-row").filter({ hasText: "Apple" })).toBeVisible();
|
||||
await expect(pageB.locator(".item-row").filter({ hasText: "Apple" }).locator(".item-qty")).toHaveText("(2)");
|
||||
|
||||
await contextB.close();
|
||||
});
|
||||
+7
-7
@@ -1,12 +1,10 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::domain::{
|
||||
DomainError, DomainResult, GroceryList, Item, Meal, SessionUser, User,
|
||||
};
|
||||
use crate::domain::{DomainError, DomainResult, GroceryList, Item, Meal, SessionUser, User};
|
||||
use crate::ports::{
|
||||
CategoryRepository, InvitationRepository, ItemRepository, ListRepository, MealIngredientRepository,
|
||||
MealRepository, NewItem, PasswordHasher, RealtimeNotifier, SessionRepository, TokenGenerator,
|
||||
UserRepository,
|
||||
CategoryRepository, InvitationRepository, ItemRepository, ListRepository,
|
||||
MealIngredientRepository, MealRepository, NewItem, PasswordHasher, RealtimeNotifier,
|
||||
SessionRepository, TokenGenerator, UserRepository,
|
||||
};
|
||||
use crate::sqlite::SqliteDatabase;
|
||||
|
||||
@@ -312,7 +310,9 @@ impl MealService {
|
||||
pub async fn create_meal(&self, name: String, description: String) -> DomainResult<Meal> {
|
||||
let meals = Arc::clone(&self.meals);
|
||||
self.db
|
||||
.run(move |txn| Box::pin(async move { meals.create_meal(txn, name, description).await }))
|
||||
.run(move |txn| {
|
||||
Box::pin(async move { meals.create_meal(txn, name, description).await })
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
+3
-16
@@ -237,11 +237,7 @@ pub fn meal_picker(meals: &[Meal], list_id: i64, csrf_token: &str) -> Markup {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn meal_form_page(
|
||||
user: &User,
|
||||
meal: Option<&Meal>,
|
||||
csrf_token: &str,
|
||||
) -> Markup {
|
||||
pub fn meal_form_page(user: &User, meal: Option<&Meal>, csrf_token: &str) -> Markup {
|
||||
let (title, action, name, description) = match meal {
|
||||
Some(meal) => (
|
||||
"Edit meal",
|
||||
@@ -276,12 +272,7 @@ pub fn meal_form_page(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn meal_page(
|
||||
user: &User,
|
||||
meal: &Meal,
|
||||
categories: &[Category],
|
||||
csrf_token: &str,
|
||||
) -> Markup {
|
||||
pub fn meal_page(user: &User, meal: &Meal, categories: &[Category], csrf_token: &str) -> Markup {
|
||||
page(
|
||||
&meal.name,
|
||||
Some(user),
|
||||
@@ -743,11 +734,7 @@ fn category_options(categories: &[Category], selected: Option<i64>) -> Markup {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn categories_panel(
|
||||
categories: &[Category],
|
||||
csrf_token: &str,
|
||||
out_of_band: bool,
|
||||
) -> Markup {
|
||||
pub fn categories_panel(categories: &[Category], csrf_token: &str, out_of_band: bool) -> Markup {
|
||||
let panel = html! {
|
||||
div class="panel-heading" {
|
||||
h2 { "Categories" }
|
||||
|
||||
Reference in New Issue
Block a user