/** * The sites this browser knows, and the logins it sets up for them. * * WHY PRESETS EXIST AT ALL. A profile was named by hand and labelled by hand, and the agent finds * the right account BY that label — so a profile called "carla-test-facebook" with an empty site * field is invisible to it. The login exists, the agent reports it has none, and neither half looks * broken. Getting it wrong was silent, and the only symptom was an agent that would not do what it * was told. * * These cannot be typed wrongly because there is nothing to type. */ import { describe, it, expect } from 'vitest'; import { SITES, get, list, profileNameFor } from '../src/sites/index.js'; describe('the presets', () => { it('covers the sites the roles actually know', () => { /* * `searchconsole` is a SURFACE rather than another login: it borrows the Google profile because * it is the same account, and exists separately because it needs that account SIGNED IN while * search on the same profile is deliberately used signed out. Without the split, learning that * Search Console cannot be read would have routed web search to a phone as well. */ expect(Object.keys(SITES).sort()).toEqual(['facebook', 'google', 'hn', 'indiehackers', 'linkedin', 'reddit', 'searchconsole', 'upwork', 'useme']); }); /* * A BORROWED PROFILE IS NOT A SECOND LOGIN. searchconsole must never mint its own profile, or the * owner signs into Google twice and the two sessions drift. */ it('and a surface that borrows a login does not claim one of its own', () => { expect(SITES.searchconsole.profile).toBe('google'); expect(SITES.searchconsole.needsLogin).toBe(true); expect(SITES.google.needsLogin).toBeUndefined(); }); /* This is the field the agent matches on. Every other decision here is a convenience; this one is the reason the file exists. */ it('gives every preset the site label the agent matches on', () => { for (const [key, s] of Object.entries(SITES)) { expect(s.site, key).toMatch(/^[a-z0-9.-]+\.[a-z]{2,}$/); expect(s.site, key).not.toMatch(/^https?:/); } }); it('produces a profile name that cannot be mistyped', () => { expect(profileNameFor('facebook')).toBe('facebook'); expect(profileNameFor('Linked In!')).toBe('linkedin'); }); /* Somebody setting up a login wants the login page, not a home page that redirects them somewhere else first. */ it('opens each one where the setting up actually happens', () => { expect(SITES.facebook.start).toMatch(/facebook\.com\/login/); expect(SITES.linkedin.start).toMatch(/linkedin\.com\/login/); // Google needs no account — what has to be cleared there is the consent page. expect(SITES.google.start).toMatch(/google\.com\/search/); }); /* * Both Facebook and LinkedIn name the device on their "was this you?" screens and both said * Linux, which is unusual enough on a home connection to be worth a second look. Google does not * ask, so it is left telling the truth. */ it('presents as Windows only where the site actually asks about the device', () => { expect(SITES.facebook.defaults.presentAs).toBe('windows'); expect(SITES.linkedin.defaults.presentAs).toBe('windows'); expect(SITES.google.defaults.presentAs).toBe(''); }); /* * A container has no fingerprint reader, so a passkey prompt waits forever for one — the failure * that cost an evening. Refused where it is offered, left alone where it is not. */ it('refuses passkeys on the sites that offer them', () => { expect(SITES.facebook.defaults.blockPasskeys).toBe(true); expect(SITES.linkedin.defaults.blockPasskeys).toBe(true); expect(SITES.google.defaults.blockPasskeys).toBe(false); }); /* Somebody about to meet a captcha, a code or a consent wall should be told which. */ it('says what is waiting on the other side', () => { for (const [key, s] of Object.entries(SITES)) expect(s.hint, key).toBeTruthy(); expect(SITES.google.hint).toMatch(/consent/i); expect(SITES.linkedin.hint).toMatch(/passkey/i); }); /* * THE EXIT IS DELIBERATELY NOT HERE ANY MORE. * * It was added to each preset after a fresh Facebook profile came out exiting from a datacentre. * That fixed the presets and left the same trap for every profile made any other way — so * routing through the tailnet became the DEFAULT for everything instead, and carrying it here * would be a second place for the same fact to be wrong. */ it('leaves the exit to the default rather than repeating it per site', () => { for (const [key, s] of Object.entries(SITES)) { expect(s.defaults.proxy, key).toBeUndefined(); } }); it('is honest about an unknown one rather than inventing it', () => { expect(get('myspace')).toBeNull(); expect(get('')).toBeNull(); }); }); describe('offering them next to what already exists', () => { it('marks the ones already set up, so a picker can offer the rest', () => { const l = list(['facebook', 'something-else']); expect(l.find((x) => x.key === 'facebook').exists).toBe(true); expect(l.find((x) => x.key === 'linkedin').exists).toBe(false); }); /* * I HAD THIS BACKWARDS, and the test asserted the wrong thing on purpose. * * The reasoning was "a hand-made profile is not the preset, and claiming otherwise hides an * unlabelled login". That holds for an UNLABELLED one and is simply wrong for a labelled one: the * site label is what the agent matches on, so a profile carrying it IS the login for that site * whatever somebody called it. Matching on the name alone offered "Set up Facebook" beside a * working Facebook login, and accepting it created an empty second one. */ it('counts a login labelled with the site, whatever it is called', () => { const l = list([{ name: 'carla-test-facebook', site: 'facebook.com' }]); const fb = l.find((x) => x.key === 'facebook'); expect(fb.exists).toBe(true); // ...and says WHICH one, so nobody has to guess whether their own profile counts. expect(fb.servedBy).toBe('carla-test-facebook'); }); it('still offers a site nothing is labelled for', () => { const l = list([{ name: 'carla-test-facebook', site: 'facebook.com' }]); expect(l.find((x) => x.key === 'linkedin').exists).toBe(false); }); /* An UNLABELLED login is invisible to the agent, so it must not silently satisfy a preset — that was the correct half of the original reasoning and it stays. */ it('does not count an unlabelled login that merely looks related', () => { expect(list([{ name: 'my-facebook-thing', site: '' }]).find((x) => x.key === 'facebook').exists).toBe(false); }); it('still accepts plain names, for a caller that has not read the labels', () => { expect(list(['facebook']).find((x) => x.key === 'facebook').exists).toBe(true); }); it('is case-insensitive about what is already there', () => { expect(list(['FaceBook']).find((x) => x.key === 'facebook').exists).toBe(true); expect(list([{ name: 'x', site: 'Facebook.com' }]).find((x) => x.key === 'facebook').exists).toBe(true); }); }); describe('freelance presets', () => { const { SITES } = require('../src/sites/index.js'); it('the growth desk rooms are known sites — reddit, hacker news, indie hackers — each opening on its login with passkeys refused', () => { for (const [k, site] of [['reddit', 'reddit.com'], ['hn', 'news.ycombinator.com'], ['indiehackers', 'indiehackers.com']]) { const s = get(k); expect(s.site).toBe(site); expect(s.start.startsWith('https://')).toBe(true); expect(s.start).toMatch(/login|sign-in/); expect(s.defaults.blockPasskeys).toBe(true); expect(s.defaults.presentAs).toBe('windows'); } }); it('useme and upwork are known sites with login starts and passkeys refused', () => { for (const k of ['useme', 'upwork']) { expect(SITES[k]).toBeTruthy(); expect(SITES[k].start).toMatch(/login/); expect(SITES[k].defaults.blockPasskeys).toBe(true); } }); }); describe('a preset may live in ANOTHER profile (a site whose only door is another site login)', () => { const { SITES, profileNameFor, borrowsProfile, list } = require('../src/sites/index.js'); it('Indie Hackers opens in the google profile — a Google sign-in in a fresh isolated profile is the one Google refuses', () => { expect(SITES.indiehackers.profile).toBe('google'); expect(profileNameFor('indiehackers')).toBe('google'); expect(borrowsProfile('indiehackers')).toBe(true); expect(SITES.indiehackers.hint).toMatch(/Google/); }); it('a preset that owns its profile is unchanged, and borrows nothing', () => { for (const k of ['facebook', 'linkedin', 'reddit', 'hn', 'google', 'useme', 'upwork']) { expect(profileNameFor(k)).toBe(k); expect(borrowsProfile(k)).toBe(false); } }); it('the listing reports the borrowed profile, so a Google login already set up counts as set up', () => { const row = list([{ name: 'google', site: 'google.com' }]).find((x) => x.key === 'indiehackers'); expect(row.profile).toBe('google'); expect(row.exists).toBe(true); }); }); describe('single-browser mode: a preset opens THE browser, never a new profile', () => { const src = require('node:fs').readFileSync(new URL('../src/server.js', import.meta.url), 'utf8'); const route = src.slice(src.indexOf("const preset = req.body && req.body.preset"), src.indexOf('const s = await pool.createSession(')); it('a PINNED preset outranks the shared browser — measured beats assumed', () => { const { pinnedProfile } = require('../src/sites/index.js'); expect(pinnedProfile('indiehackers')).toBe('google'); expect(pinnedProfile('hn')).toBeNull(); expect(route).toContain('const pinned = sites.pinnedProfile(req.body.preset)'); expect(route).toContain('profileName = pinned || served || oneBrowser || sites.profileNameFor(req.body.preset)'); expect(route).toContain('if (!pinned && !served && !oneBrowser && !sites.borrowsProfile(req.body.preset))'); }); it('a login that ALREADY EXISTS beats the shared browser — Reddit and Hacker News live in their own profiles', () => { const { servedProfile } = require('../src/sites/index.js'); const have = [{ name: 'reddit', site: 'reddit.com' }, { name: 'hn', site: 'news.ycombinator.com' }, { name: 'facebook', site: 'facebook.com' }]; expect(servedProfile('reddit', have)).toBe('reddit'); expect(servedProfile('hn', have)).toBe('hn'); expect(servedProfile('upwork', have)).toBeNull(); // nobody signed in anywhere → the shared browser expect(servedProfile('reddit', [{ name: 'anything', site: 'reddit.com' }])).toBe('anything'); // matched on the label too expect(route).toContain('const served = pinned ? null : sites.servedProfile(req.body.preset, pool.listProfilesDetailed())'); expect(route).toContain('profileName = pinned || served || oneBrowser || sites.profileNameFor(req.body.preset)'); }); it('reads the setting and uses browserProfile as the profile', () => { expect(route).toMatch(/settingsStore\.read\(\)/); expect(route).toMatch(/single\.singleBrowser \? \(single\.browserProfile \|\| 'facebook'\) : null/); expect(route).toContain('profileName = pinned || served || oneBrowser || sites.profileNameFor(req.body.preset)'); }); it('never writes a site label onto the shared browser — that would hide every other login from the agent', () => { expect(route).toContain('if (!pinned && !served && !oneBrowser && !sites.borrowsProfile(req.body.preset)) {'); }); });