mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-20 11:19:56 +08:00
test: arrow hide signal chain (4-step) + stale session-ended assertion
8 new tests verify the sidebarOpened → background → content → welcome signal chain. Updates stale "(session ended)" test that checked for text removed in a prior commit. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -165,8 +165,10 @@ describe('sidebar JS (sidepanel.js)', () => {
|
|||||||
expect(js).toContain("data.agentStatus !== 'processing'");
|
expect(js).toContain("data.agentStatus !== 'processing'");
|
||||||
});
|
});
|
||||||
|
|
||||||
test('orphaned thinking cleanup adds (session ended) notice', () => {
|
test('orphaned thinking cleanup removes thinking dots silently', () => {
|
||||||
expect(js).toContain('(session ended)');
|
// Thinking dots are removed when agent is idle — no "(session ended)"
|
||||||
|
// notice, which was removed as noisy false-positive UX
|
||||||
|
expect(js).toContain('thinking.remove()');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('sendMessage renders user bubble + thinking dots optimistically', () => {
|
test('sendMessage renders user bubble + thinking dots optimistically', () => {
|
||||||
@@ -1321,12 +1323,80 @@ describe('sidebar auto-open (background.js)', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('extension dispatches gstack-extension-ready event', () => {
|
describe('sidebar arrow hint hide flow (4-step signal chain)', () => {
|
||||||
|
// The arrow hint on the welcome page should ONLY hide when the sidebar
|
||||||
|
// is actually opened, not when the extension content script loads.
|
||||||
|
//
|
||||||
|
// Signal flow:
|
||||||
|
// 1. sidepanel.js connects → sends { type: 'sidebarOpened' } to background
|
||||||
|
// 2. background.js receives → relays to active tab's content script
|
||||||
|
// 3. content.js receives 'sidebarOpened' → dispatches 'gstack-extension-ready'
|
||||||
|
// 4. welcome.html listens for 'gstack-extension-ready' → hides arrow
|
||||||
|
//
|
||||||
const contentSrc = fs.readFileSync(path.join(ROOT, '..', 'extension', 'content.js'), 'utf-8');
|
const contentSrc = fs.readFileSync(path.join(ROOT, '..', 'extension', 'content.js'), 'utf-8');
|
||||||
|
const bgSrc = fs.readFileSync(path.join(ROOT, '..', 'extension', 'background.js'), 'utf-8');
|
||||||
|
const spSrc = fs.readFileSync(path.join(ROOT, '..', 'extension', 'sidepanel.js'), 'utf-8');
|
||||||
|
const welcomeSrc = fs.readFileSync(path.join(ROOT, 'src', 'welcome.html'), 'utf-8');
|
||||||
|
|
||||||
test('content.js dispatches gstack-extension-ready CustomEvent', () => {
|
// Step 1: sidepanel sends sidebarOpened when connected
|
||||||
|
test('step 1: sidepanel sends sidebarOpened message on connect', () => {
|
||||||
|
expect(spSrc).toContain("{ type: 'sidebarOpened' }");
|
||||||
|
// Should be in updateConnection, after setConnState('connected')
|
||||||
|
const connectFn = spSrc.slice(
|
||||||
|
spSrc.indexOf('function updateConnection('),
|
||||||
|
spSrc.indexOf('function updateConnection(') + 800,
|
||||||
|
);
|
||||||
|
expect(connectFn).toContain('sidebarOpened');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Step 2: background.js accepts and relays sidebarOpened
|
||||||
|
test('step 2: background.js allows sidebarOpened message type', () => {
|
||||||
|
expect(bgSrc).toContain("'sidebarOpened'");
|
||||||
|
// Must be in ALLOWED_TYPES
|
||||||
|
const allowedBlock = bgSrc.slice(
|
||||||
|
bgSrc.indexOf('ALLOWED_TYPES'),
|
||||||
|
bgSrc.indexOf('ALLOWED_TYPES') + 300,
|
||||||
|
);
|
||||||
|
expect(allowedBlock).toContain('sidebarOpened');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('step 2: background.js relays sidebarOpened to active tab content script', () => {
|
||||||
|
expect(bgSrc).toContain("msg.type === 'sidebarOpened'");
|
||||||
|
// Should send to active tab via chrome.tabs.sendMessage
|
||||||
|
const handler = bgSrc.slice(
|
||||||
|
bgSrc.indexOf("msg.type === 'sidebarOpened'"),
|
||||||
|
bgSrc.indexOf("msg.type === 'sidebarOpened'") + 400,
|
||||||
|
);
|
||||||
|
expect(handler).toContain('chrome.tabs.sendMessage');
|
||||||
|
expect(handler).toContain("{ type: 'sidebarOpened' }");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Step 3: content.js fires gstack-extension-ready ONLY on sidebarOpened
|
||||||
|
test('step 3: content.js dispatches extension-ready on sidebarOpened message', () => {
|
||||||
|
expect(contentSrc).toContain("msg.type === 'sidebarOpened'");
|
||||||
expect(contentSrc).toContain("new CustomEvent('gstack-extension-ready')");
|
expect(contentSrc).toContain("new CustomEvent('gstack-extension-ready')");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('step 3: content.js does NOT auto-fire extension-ready on load', () => {
|
||||||
|
// The old pattern was: fire immediately when content script loads.
|
||||||
|
// Now it should only fire when sidebarOpened message arrives.
|
||||||
|
// Check there's no top-level dispatchEvent outside the message handler.
|
||||||
|
const beforeListener = contentSrc.slice(0, contentSrc.indexOf('chrome.runtime.onMessage'));
|
||||||
|
expect(beforeListener).not.toContain("dispatchEvent(new CustomEvent('gstack-extension-ready'))");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Step 4: welcome page hides arrow on gstack-extension-ready
|
||||||
|
test('step 4: welcome page hides arrow on gstack-extension-ready event', () => {
|
||||||
|
expect(welcomeSrc).toContain("'gstack-extension-ready'");
|
||||||
|
expect(welcomeSrc).toContain("classList.add('hidden')");
|
||||||
|
});
|
||||||
|
|
||||||
|
test('step 4: welcome page does NOT auto-hide via status pill polling', () => {
|
||||||
|
// The old fallback (checkPill/gstack-status-pill) would hide the arrow
|
||||||
|
// as soon as the content script injected the pill, even without sidebar open.
|
||||||
|
expect(welcomeSrc).not.toContain('checkPill');
|
||||||
|
expect(welcomeSrc).not.toContain('gstack-status-pill');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('sidebar auth race prevention', () => {
|
describe('sidebar auth race prevention', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user