mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
SPC, Pars and Osage have no explorer and no public node, the devnet has no explorer, and the Hanzo testnet explorer has no DNS name. Their registry entries put links to names that do not resolve on every page (the "SPC L1" and "Pars L1" cards, the chain switcher, the network selector), and the Pars entry sent a node request to api.pars.network on every page load that failed with 502. The P-Chain still lists SPC and Pars; their cards render without a link. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
106 lines
4.4 KiB
TypeScript
106 lines
4.4 KiB
TypeScript
import { describe, expect, it, beforeEach } from 'vitest';
|
|
|
|
import {
|
|
getChainsForNetwork,
|
|
getCurrentChain,
|
|
getCurrentNetwork,
|
|
isPrimaryNetworkExplorer,
|
|
isWhiteLabelMode,
|
|
} from './chainRegistry';
|
|
|
|
// Drives the registry off a simulated request host, exactly like the browser
|
|
// (getHostname() reads window.location.hostname). window.__envs is emptied so
|
|
// no NEXT_PUBLIC_* override leaks in — we assert the bundled defaults.
|
|
function atHost(hostname: string) {
|
|
// Minimal browser global so isBrowser() is true and getHostname() reads the
|
|
// simulated request host — no jsdom needed.
|
|
(globalThis as unknown as { window: unknown }).window = { location: { hostname }, __envs: {} };
|
|
}
|
|
|
|
// Mirrors the pure logic of ui/snippets/topBar/ChainSwitcher.tsx: the lux
|
|
// primary (C-Chain) host shows every chain; a brand explorer shows only chains
|
|
// sharing its brand. Returns the chain names the switcher would render.
|
|
function switcherChainNames(): Array<string> {
|
|
const current = getCurrentChain();
|
|
const all = getChainsForNetwork(getCurrentNetwork().network);
|
|
const isMain = current.name === 'C-Chain';
|
|
return (isMain ? all : all.filter((c) => c.branding.brandName === current.branding.brandName)).map((c) => c.name);
|
|
}
|
|
|
|
describe('chain-visibility rule', () => {
|
|
beforeEach(() => atHost('localhost'));
|
|
|
|
describe('Lux primary explorer (explore.lux.network) = UNIVERSAL (shows everything)', () => {
|
|
beforeEach(() => atHost('explore.lux.network'));
|
|
|
|
it('is the primary-network explorer', () => {
|
|
expect(isWhiteLabelMode()).toBe(false);
|
|
expect(isPrimaryNetworkExplorer()).toBe(true);
|
|
expect(getCurrentChain().name).toBe('C-Chain');
|
|
});
|
|
|
|
// The switcher lists the chains that have an explorer to switch to, and
|
|
// no others: every entry is a link, and a link to a name that does not
|
|
// resolve is a dead end on every page.
|
|
it('lists exactly the mainnet chains with an explorer', () => {
|
|
expect(switcherChainNames()).toEqual([ 'C-Chain', 'Zoo', 'Hanzo' ]);
|
|
});
|
|
});
|
|
|
|
describe('Brand explorers = OWN-ONLY (no lux primary, no other orgs)', () => {
|
|
const cases = [
|
|
{ host: 'explore.hanzo.network', name: 'Hanzo', brandName: 'Hanzo AI' },
|
|
{ host: 'explore.zoo.network', name: 'Zoo', brandName: 'Zoo Chain' },
|
|
];
|
|
|
|
it.each(cases)('$host is a registered L2, NOT the primary explorer (no leak)', ({ host, brandName }) => {
|
|
atHost(host);
|
|
expect(isWhiteLabelMode()).toBe(false);
|
|
expect(isPrimaryNetworkExplorer()).toBe(false);
|
|
expect(getCurrentChain().vm).toBe('L2');
|
|
expect(getCurrentChain().branding.brandName).toBe(brandName);
|
|
});
|
|
|
|
it.each(cases)('$host switcher shows ONLY its own chain (no lux-primary, no other orgs)', ({ host, name }) => {
|
|
atHost(host);
|
|
expect(switcherChainNames()).toEqual([ name ]);
|
|
});
|
|
});
|
|
|
|
// The footer renders branding.sourceUrl and branding.orgName verbatim, so a
|
|
// foreign org in either is a brand leak a reader can see. It shipped once as a
|
|
// hardcoded github.com/luxfi/explore version link on every brand's footer.
|
|
describe('a brand host never surfaces another org', () => {
|
|
const foreign: Record<string, Array<string>> = {
|
|
'explore.hanzo.ai': [ 'luxfi', 'lux.network', 'zoo', 'pars' ],
|
|
'explore.hanzo.network': [ 'luxfi', 'lux.network', 'zoo', 'pars' ],
|
|
'explore.zoo.network': [ 'luxfi', 'lux.network', 'hanzo', 'pars' ],
|
|
};
|
|
|
|
it.each(Object.entries(foreign))('%s footer names only its own org', (host, others) => {
|
|
atHost(host);
|
|
const { orgName, sourceUrl, websiteUrl, githubUrl } = getCurrentChain().branding;
|
|
const rendered = [ orgName, sourceUrl, websiteUrl, githubUrl ].join(' ').toLowerCase();
|
|
others.forEach((org) => expect(rendered).not.toContain(org));
|
|
});
|
|
|
|
it('lux keeps its own source link', () => {
|
|
atHost('explore.lux.network');
|
|
expect(getCurrentChain().branding.sourceUrl).toBe('https://github.com/luxfi/explore');
|
|
});
|
|
|
|
it('hanzo carries the legal entity used across hanzo surfaces', () => {
|
|
atHost('explore.hanzo.ai');
|
|
expect(getCurrentChain().branding.orgName).toBe('Hanzo AI, Inc.');
|
|
});
|
|
});
|
|
|
|
describe('keystone: unregistered white-label hosts are NEVER the primary explorer', () => {
|
|
it('does not leak the lux primary network to an unknown host', () => {
|
|
atHost('explore.unknown.example');
|
|
expect(isWhiteLabelMode()).toBe(true);
|
|
expect(isPrimaryNetworkExplorer()).toBe(false);
|
|
});
|
|
});
|
|
});
|