Fix compact calendar events and stabilize E2E execution
Some checks failed
Deploy Sokko G / deploy (push) Failing after 2s
Some checks failed
Deploy Sokko G / deploy (push) Failing after 2s
This commit is contained in:
parent
748415082b
commit
2bff58f08c
6 changed files with 120 additions and 7 deletions
|
|
@ -26,3 +26,5 @@
|
|||
{"id":"int-903a25fde459880bbbadc2764da920a2","kind":"field_change","created_at":"2026-09-10T16:58:56.754421196Z","actor":"Shinuwa","issue_id":"sokko-g-hf6","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Unified confirmed-state queue for all writes; imports use current-state updaters; atomic creation/link/deletion and synchronous transaction abort. Removed obsolete checkpoints. Deterministic concurrency/failure tests and real IndexedDB abort E2E pass; full suite 15/15 and npm run check pass."}}
|
||||
{"id":"int-16ba759581961e395e133df1c6019895","kind":"field_change","created_at":"2026-09-10T17:21:13.173981957Z","actor":"Shinuwa","issue_id":"sokko-g-ra9","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Implemented quota coalescing and shared helpers. npm run check and all 15 E2E tests with --workers=2 pass; default concurrency timeouts tracked separately."}}
|
||||
{"id":"int-df984435537f78d51a7a309feda1109c","kind":"field_change","created_at":"2026-09-10T17:21:18.79044889Z","actor":"Shinuwa","issue_id":"sokko-g-ckq","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Implemented quota coalescing and shared helpers. npm run check and all 15 E2E tests with --workers=2 pass; default concurrency timeouts tracked separately."}}
|
||||
{"id":"int-300128a7d6ed7fa43c5f43c7cb0b9dad","kind":"field_change","created_at":"2026-09-11T06:50:23.200542022Z","actor":"Shinuwa","issue_id":"sokko-g-v02","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Default E2E concurrency capped at two workers with failure traces; compact calendar titles kept in flow and sm padding corrected. Desktop/mobile geometry and editing regressions added. npm run check:full passed; second full E2E run passed all 17 tests without retries."}}
|
||||
{"id":"int-a54950bb4a7dbb177188a5ec02e9d9fd","kind":"field_change","created_at":"2026-09-11T06:50:28.175047619Z","actor":"Shinuwa","issue_id":"sokko-g-328","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Default E2E concurrency capped at two workers with failure traces; compact calendar titles kept in flow and sm padding corrected. Desktop/mobile geometry and editing regressions added. npm run check:full passed; second full E2E run passed all 17 tests without retries."}}
|
||||
|
|
|
|||
|
|
@ -777,6 +777,7 @@ Date picker et menus compacts :
|
|||
- `nds-event-surface[data-size="md"]` vise les surfaces à partir de `44px` et affiche le titre et la metadata secondaire, par exemple l'heure ;
|
||||
- `nds-event-surface[data-size="sm"]` vise les surfaces autour de `22px` et masque la metadata secondaire ;
|
||||
- `nds-event-surface[data-size="xs"]` vise les surfaces ultra-fines autour de `10px` et affiche uniquement le titre en taille réduite ;
|
||||
- les titres compacts restent dans le flux pour donner une hauteur au bouton, même si la surface ne définit qu'une hauteur minimale ; en `sm`, bordures et padding doivent tenir avec la ligne de titre dans les `22px` ;
|
||||
- `nds-event-surface[data-color="#8b5cf6"]` expose la couleur métier de l'event ; la variable inline `--nds-event-color` applique cette couleur au fond et a la bordure ;
|
||||
- le hover utilise une superposition sombre legere pour rester lisible sur une couleur dynamique inconnue du Sass ;
|
||||
- les couleurs de fond des events restent métier et ne sont pas des variants NDS ;
|
||||
|
|
|
|||
|
|
@ -61,6 +61,13 @@ npm run check
|
|||
|
||||
Cette commande vérifie la configuration Node/Vite, lance les tests, puis exécute le build React.
|
||||
|
||||
Pour inclure les parcours navigateur, lancer `npm run check:full`. Les deux
|
||||
validations sont exécutées successivement pour éviter la concurrence avec le build.
|
||||
La suite E2E utilise deux workers par défaut pour limiter la contention lors du
|
||||
chargement initial des outils par Vite. Le parallélisme reste ajustable avec
|
||||
`npm run test:e2e -- --workers=4`. Les traces des tests en échec sont conservées
|
||||
dans `test-results` et consultables depuis le rapport Playwright.
|
||||
|
||||
## Contenu éditable
|
||||
|
||||
Les contenus maintenus à la main sont regroupés dans `website/public/data`.
|
||||
|
|
|
|||
106
e2e/calendar-layout.spec.js
Normal file
106
e2e/calendar-layout.spec.js
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// Rôle : vérifie la lisibilité et la zone cliquable des événements calendrier denses.
|
||||
/* global getComputedStyle */
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { resetSokkoStorage } from "./helpers/storage.js";
|
||||
|
||||
async function seedCalendars(page) {
|
||||
await resetSokkoStorage(page);
|
||||
await page.evaluate(async () => {
|
||||
const db = await import("/src/utils/indexedDbStorage.js");
|
||||
const dateKey = (day) => {
|
||||
const now = new Date();
|
||||
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
||||
};
|
||||
await db.setToolboxSnapshot([{
|
||||
id: "calendar-layout",
|
||||
name: "Calendar layout",
|
||||
moduleColumns: 1,
|
||||
modules: [
|
||||
{ id: "week", type: "calendar", title: "Week" },
|
||||
{ id: "month", type: "calendar", title: "Month" }
|
||||
]
|
||||
}], {}, {
|
||||
"calendar-layout:week": {
|
||||
initialized: true,
|
||||
viewMode: "week",
|
||||
events: [30, 60, 120].map((duration, index) => ({
|
||||
id: `week-${index}`, title: `Raid ${duration}`, dayIndex: index,
|
||||
startMinutes: 600, endMinutes: 600 + duration, color: "violet"
|
||||
}))
|
||||
},
|
||||
"calendar-layout:month": {
|
||||
initialized: true,
|
||||
viewMode: "month",
|
||||
events: [0, 1, 2, 3].map((index) => ({
|
||||
id: `month-${index}`, title: `Event ${index}`, repeat: "none",
|
||||
startDate: dateKey(index < 3 ? 10 : 20), endDate: dateKey(index < 3 ? 10 : 20),
|
||||
color: "gold"
|
||||
}))
|
||||
}
|
||||
});
|
||||
});
|
||||
await page.goto("/#/toolbox/calendar-layout");
|
||||
await page.reload();
|
||||
}
|
||||
|
||||
async function expectTitleFits(surface) {
|
||||
await surface.scrollIntoViewIfNeeded();
|
||||
const box = await surface.evaluate((element) => {
|
||||
const button = element.querySelector("button");
|
||||
const title = button.querySelector("strong");
|
||||
const outer = element.getBoundingClientRect();
|
||||
const inner = button.getBoundingClientRect();
|
||||
const text = title.getBoundingClientRect();
|
||||
const style = getComputedStyle(element);
|
||||
return {
|
||||
height: outer.height,
|
||||
buttonHeight: inner.height,
|
||||
titleHeight: text.height,
|
||||
topSpace: text.top - outer.top - parseFloat(style.borderTopWidth),
|
||||
bottomSpace: outer.bottom - parseFloat(style.borderBottomWidth) - text.bottom,
|
||||
buttonTopSpace: text.top - inner.top,
|
||||
buttonBottomSpace: inner.bottom - text.bottom
|
||||
};
|
||||
});
|
||||
expect(box.titleHeight).toBeGreaterThan(0);
|
||||
expect(box.buttonHeight).toBeGreaterThanOrEqual(box.height - 2);
|
||||
for (const gap of [box.topSpace, box.bottomSpace, box.buttonTopSpace, box.buttonBottomSpace]) {
|
||||
expect(gap, JSON.stringify(box)).toBeGreaterThanOrEqual(-0.5);
|
||||
}
|
||||
}
|
||||
|
||||
for (const width of [1440, 390]) {
|
||||
test(`dense calendar titles fit and remain editable at ${width}px`, async ({ page }, testInfo) => {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
await page.clock.setFixedTime(new Date("2026-09-01T12:00:00Z"));
|
||||
const errors = [];
|
||||
page.on("pageerror", (error) => errors.push(error.message));
|
||||
await seedCalendars(page);
|
||||
const week = page.locator('[data-module-type="calendar"]').first();
|
||||
const month = page.locator('[data-module-type="calendar"]').last();
|
||||
await expect(week.locator(".calendar-event")).toHaveCount(3);
|
||||
await expect(month.locator(".calendar-month-bar")).toHaveCount(4);
|
||||
for (const size of ["xs", "sm", "md"]) {
|
||||
const surface = week.locator(`.calendar-event[data-size="${size}"]`);
|
||||
await expect(surface).toHaveCount(1);
|
||||
await expectTitleFits(surface);
|
||||
}
|
||||
for (const size of ["xs", "sm"]) {
|
||||
const surfaces = month.locator(`.calendar-month-bar[data-size="${size}"]`);
|
||||
await expect(surfaces).toHaveCount(size === "xs" ? 3 : 1);
|
||||
for (const surface of await surfaces.all()) await expectTitleFits(surface);
|
||||
}
|
||||
await month.screenshot({ path: testInfo.outputPath("month.png") });
|
||||
await week.screenshot({ path: testInfo.outputPath("week.png") });
|
||||
for (const [module, selector, title] of [
|
||||
[week, ".calendar-event", "Raid 30"],
|
||||
[month, ".calendar-month-bar", "Event 0"]
|
||||
]) {
|
||||
const button = module.locator(`${selector}[data-size="xs"] button`).first();
|
||||
await button.click();
|
||||
await expect(module.getByLabel("Titre", { exact: true })).toHaveValue(title);
|
||||
await module.getByRole("button", { name: "Annuler", exact: true }).click();
|
||||
}
|
||||
expect(errors).toEqual([]);
|
||||
});
|
||||
}
|
||||
|
|
@ -4,10 +4,12 @@ import { defineConfig, devices } from "@playwright/test";
|
|||
export default defineConfig({
|
||||
testDir: "./e2e",
|
||||
fullyParallel: true,
|
||||
// Le serveur Vite partagé compile les outils lazy à la première visite.
|
||||
workers: 2,
|
||||
reporter: [["list"], ["html", { open: "never" }]],
|
||||
use: {
|
||||
baseURL: "http://localhost:5173",
|
||||
trace: "on-first-retry",
|
||||
trace: "retain-on-failure",
|
||||
screenshot: "only-on-failure"
|
||||
},
|
||||
webServer: {
|
||||
|
|
|
|||
|
|
@ -44,12 +44,11 @@
|
|||
|
||||
.nds-event-surface[data-size="sm"] button {
|
||||
display: block;
|
||||
padding: 4px 7px;
|
||||
padding: 3px 7px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nds-event-surface[data-size="xs"] button {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 0 4px;
|
||||
text-align: center;
|
||||
|
|
@ -92,10 +91,6 @@
|
|||
}
|
||||
|
||||
.nds-event-surface[data-size="xs"] strong {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 4px;
|
||||
left: 4px;
|
||||
max-width: 100%;
|
||||
height: 10px;
|
||||
font-size: 8px;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue