feat: A20 phase 3 LOT 2 — settings + local workspace verts en CSP preview (v7.39.0)
Ajout : - 2 gates csp_preview de plus : settings (composant lie, overlay visible) et local workspace (recherche focalisee via Alpine.nextTick, chips filtre en SVG via bindSvg, 0 erreur) → 3 surfaces vertes sous build CSP : library, settings, local workspace. Changed : - settings : window.history.back()/new Date(...) → methodes historyBack/fmtLastLogin/fmtAuditDate ; ?. → ternaires. - local workspace : x-data="_wsInitData" → registre wsInitData() ; 14 x-html → x-init + Alpine.effect (bindSvg/bindFileIcon/bindNodeIcon/ bindChildren/bindPreview) ; $nextTick+$refs arrow → toggleSearch() ; window.FlowDeck.* → createPageAt/createFolderAt ; ?. → ternaires ; @contextmenu="_wsInitData.*" → appel de methode. Piesges resolus (CHANGELOG en details) : - snapshot ji du build CSP = valeurs globalThis au boot → l'objet mis sur window avant Alpine est banni (« Accessing global variables ») → objet porte par une CONST LEXICALE (non propriete globalThis) + factory Alpine.data → MEME objet partage, reactivite intacte. - bloc preview hors div racine (structure pre-existante, masquee par le fallback window standard) → composant wsPreview DELEGUANT vers _wsInitData via Alpine.reactive (wrapper unique : les magics $nextTick ne sont redefinissables qu'une fois). - .env local : RATE_LIMIT_REQUESTS=600 (rafales E2E vs 60/min par IP ; defaut produit inchange). suite **1093/1093** · ruff OK · eslint 0/0 · E2E **5/5** (3 csp_preview + 2 smoke) · CSP preview ET standard = 0 erreur sur /local-workspace · docs a jour
This commit is contained in:
+41
-8
@@ -53,13 +53,8 @@ async function login(page) {
|
||||
}
|
||||
}
|
||||
|
||||
test('A20-ph3 : library sous build Alpine CSP', async ({ page }) => {
|
||||
await login(page);
|
||||
await page.goto(`${FD_BASE}/library`, { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForTimeout(600);
|
||||
|
||||
// le composant est lié par le registre Alpine.data (scope CSP)
|
||||
const bound = await page.evaluate(() => {
|
||||
async function assertBound(page) {
|
||||
return page.evaluate(() => {
|
||||
const el = document.querySelector('[x-data]');
|
||||
if (!el || !window.Alpine) return 'absent';
|
||||
try {
|
||||
@@ -69,7 +64,45 @@ test('A20-ph3 : library sous build Alpine CSP', async ({ page }) => {
|
||||
return 'throw:' + e.message;
|
||||
}
|
||||
});
|
||||
expect(bound).toBe('ok');
|
||||
}
|
||||
|
||||
test('A20-ph3 : settings sous build Alpine CSP', async ({ page }) => {
|
||||
await login(page);
|
||||
await page.goto(`${FD_BASE}/settings`, { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForTimeout(600);
|
||||
expect(await assertBound(page)).toBe('ok');
|
||||
await expect(page.locator('.settings-overlay')).toBeVisible();
|
||||
});
|
||||
|
||||
test('A20-ph3 : local workspace sous build Alpine CSP', async ({ page }) => {
|
||||
await login(page);
|
||||
await page.goto(`${FD_BASE}/local-workspace`, { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForTimeout(600);
|
||||
expect(await assertBound(page)).toBe('ok');
|
||||
|
||||
// recherche : toggleSearch() (méthode réelle) + focus Alpine.nextTick
|
||||
await page.click('button.ws-icon-btn[title="Search"]');
|
||||
await page.waitForTimeout(400);
|
||||
const focused = await page.evaluate(
|
||||
() => document.activeElement && document.activeElement.getAttribute('x-ref') === 'searchInput'
|
||||
);
|
||||
expect(focused).toBe(true);
|
||||
|
||||
// chips filtre : bindSvg() via x-init (x-html interdit en CSP) —
|
||||
// x-init tourne même si la rangée est masquée (x-show=filterType)
|
||||
const svg = await page.evaluate(
|
||||
() => (document.querySelector('button.filter-chip[title="Folders"]') || {}).innerHTML || ''
|
||||
);
|
||||
expect(svg).toContain('<svg');
|
||||
});
|
||||
|
||||
test('A20-ph3 : library sous build Alpine CSP', async ({ page }) => {
|
||||
await login(page);
|
||||
await page.goto(`${FD_BASE}/library`, { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForTimeout(600);
|
||||
|
||||
// le composant est lié par le registre Alpine.data (scope CSP)
|
||||
expect(await assertBound(page)).toBe('ok');
|
||||
|
||||
// icône du empty-state : x-html remplacé par x-init + Alpine.effect
|
||||
await expect(page.locator('#lib-empty .empty-icon')).toBeVisible({ timeout: 8000 });
|
||||
|
||||
Reference in New Issue
Block a user