mirror of
https://github.com/hanzo-apps/tabs.git
synced 2026-10-30 15:04:29 +00:00
The cloud says how many tabs may stream at once (entitlements.tabs: 0 none, N a cap, -1 no cap). Panes past it are kept and covered with a link to the plans instead of being minted. A cloud that does not say enforces nothing. A Playwright spec drives the signed-in workspace against the registry's real shape: the tunnel grant, the framed shell, the cap, the unmetered case.
64 lines
2.4 KiB
TypeScript
64 lines
2.4 KiB
TypeScript
import { over, streams } from '../lib/plan';
|
|
import type { Binding } from '../lib/panes';
|
|
|
|
const shell = (machine: string, name = 'shell-1'): Binding => ({ kind: 'shell', shell: { machine, name } });
|
|
const bind: Record<string, Binding> = {
|
|
p0: shell('a'),
|
|
p1: { kind: 'page', url: 'https://example.com' },
|
|
p2: { kind: 'screen', machine: 'b' },
|
|
p3: shell('a', 'shell-2'),
|
|
p4: { kind: 'gone', shell: { machine: 'c', name: 'shell-1' } } as Binding,
|
|
};
|
|
const order = ['p0', 'p1', 'p2', 'p3', 'p4'];
|
|
|
|
describe('the panes past the plan', () => {
|
|
it('keeps the first N streamed panes and covers the rest, in layout order', () => {
|
|
expect([...over(order, bind, 2)]).toEqual(['p3']);
|
|
expect([...over(order, bind, 1)]).toEqual(['p2', 'p3']);
|
|
});
|
|
|
|
it('counts only a live shell or screen: a page, a gone machine, an empty pane stream nothing', () => {
|
|
expect([...over(['p1', 'p4'], bind, 0)]).toEqual([]);
|
|
});
|
|
|
|
it('streams nothing at 0, enforces nothing at -1 or when not told', () => {
|
|
expect([...over(order, bind, 0)]).toEqual(['p0', 'p2', 'p3']);
|
|
expect(over(order, bind, -1).size).toBe(0);
|
|
expect(over(order, bind, null).size).toBe(0);
|
|
});
|
|
|
|
it('hands a closed pane\'s place to the next one along', () => {
|
|
expect([...over(['p2', 'p3'], bind, 2)]).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('the plan as the cloud answers it', () => {
|
|
const answer = (body: unknown, ok = true) => {
|
|
global.fetch = jest.fn().mockResolvedValue({ ok, json: async () => body }) as unknown as typeof fetch;
|
|
};
|
|
|
|
it('reads the integer `tabs`', async () => {
|
|
answer({ tier: 'dev', apps: {}, tabs: 2 });
|
|
await expect(streams('t')).resolves.toBe(2);
|
|
expect(global.fetch).toHaveBeenCalledWith(
|
|
'https://api.hanzo.ai/v1/entitlements',
|
|
expect.objectContaining({ headers: { Authorization: 'Bearer t' } }),
|
|
);
|
|
answer({ tabs: 0 });
|
|
await expect(streams('t')).resolves.toBe(0);
|
|
answer({ tabs: -1 });
|
|
await expect(streams('t')).resolves.toBe(-1);
|
|
});
|
|
|
|
it('says null, which is no limit, when the cloud does not say', async () => {
|
|
answer({ tier: 'enterprise', apps: {} });
|
|
await expect(streams('t')).resolves.toBeNull();
|
|
answer({ tabs: '2' });
|
|
await expect(streams('t')).resolves.toBeNull();
|
|
answer({ tabs: 1.5 });
|
|
await expect(streams('t')).resolves.toBeNull();
|
|
answer({}, false);
|
|
await expect(streams('t')).resolves.toBeNull();
|
|
});
|
|
});
|