diff design_system/test/storybook_test.js @ 253:fdf3816959cb

[ui] Add Sonner-like notification stack Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Tue, 04 Aug 2026 12:21:19 -0700
parents 7a7581f040e8
children 2b6e732087ff
line wrap: on
line diff
--- a/design_system/test/storybook_test.js	Tue Aug 04 11:57:16 2026 -0700
+++ b/design_system/test/storybook_test.js	Tue Aug 04 12:21:19 2026 -0700
@@ -438,6 +438,81 @@
       await notificationScope.locator('article').count(),
       3,
     );
+    await page.waitForFunction(() =>
+      [...document.querySelectorAll(
+        'zen-notifications article',
+      )].some(article => article.dataset.depth === '2')
+    );
+    const collapsedStack = await notificationScope.locator(
+      '[data-zen-notification-stack]',
+    ).evaluate(stack => {
+      const articles = [...stack.querySelectorAll('article')];
+      return {
+        depths: articles.map(article => article.dataset.depth),
+        height: stack.getBoundingClientRect().height,
+        positions: articles.map(article =>
+          getComputedStyle(article).position
+        ),
+        transforms: articles.map(article =>
+          getComputedStyle(article).transform
+        ),
+      };
+    });
+    assert.deepEqual(collapsedStack.depths, ['2', '1', '0']);
+    assert.deepEqual(
+      collapsedStack.positions,
+      ['absolute', 'absolute', 'absolute'],
+    );
+    await notificationScope.locator('article').last().hover();
+    await page.waitForTimeout(300);
+    const expandedStack = await notificationScope.locator(
+      '[data-zen-notification-stack]',
+    ).evaluate(stack => ({
+      height: stack.getBoundingClientRect().height,
+      rects: [...stack.querySelectorAll('article')].map(article => {
+        const bounds = article.getBoundingClientRect();
+        return {
+          bottom: bounds.bottom,
+          left: bounds.left,
+          right: bounds.right,
+          top: bounds.top,
+        };
+      }),
+      tops: [...stack.querySelectorAll('article')].map(
+        article => Math.round(article.getBoundingClientRect().top),
+      ),
+      transforms: [...stack.querySelectorAll('article')].map(
+        article => getComputedStyle(article).transform,
+      ),
+    }));
+    assert.ok(expandedStack.height > collapsedStack.height);
+    assert.equal(new Set(expandedStack.tops).size, 3);
+    const expandedGaps = [
+      expandedStack.rects[1].top - expandedStack.rects[0].bottom,
+      expandedStack.rects[2].top - expandedStack.rects[1].bottom,
+    ];
+    for (const gap of expandedGaps) {
+      assert.ok(gap >= 10 && gap <= 14, JSON.stringify(expandedGaps));
+    }
+    assert.notDeepEqual(
+      expandedStack.transforms,
+      collapsedStack.transforms,
+    );
+    const gapX =
+      (expandedStack.rects[0].left + expandedStack.rects[0].right) / 2;
+    const gapY =
+      (expandedStack.rects[0].bottom + expandedStack.rects[1].top) / 2;
+    await page.mouse.move(gapX, gapY);
+    await page.waitForTimeout(100);
+    const gapState = await notificationScope.locator(
+      '[data-zen-notification-stack]',
+    ).evaluate(stack => ({
+      height: stack.getBoundingClientRect().height,
+      hovered: stack.matches(':hover'),
+    }));
+    assert.equal(gapState.hovered, true);
+    assert.ok(gapState.height >= expandedStack.height - 1);
+    await page.mouse.move(0, 0);
 
     const actionScope = await page.evaluate(() => {
       const scope = document.createElement('zen-notifications');
@@ -522,7 +597,7 @@
         },
       ));
     });
-    assert.equal(await actionArticle.count(), 0);
+    await actionArticle.waitFor({ state: 'detached' });
 
     await page.evaluate(() => {
       const scope = document.createElement('zen-notifications');