
Logga in i ett setup-projekt och spara tillståndet efter ett synligt kvitto. Låt lästestet starta i en ny browser context med filen. Kontrollera separat att samma skyddade sida kräver inloggning utan filen och med en ogiltig session.
1. Förbered en lokal testapp
Playwright-inloggning blir lättare att felsöka om du skiljer på själva inloggningen och testerna som använder den. Här bygger du en liten app med ett syntetiskt konto, en skyddad kontosida och en cookie som pekar på en session i serverns minne. Det finns ingen extern tjänst, databas eller riktig användare i övningen. Resultatet är ett körbart prov för återanvänd autentisering, inte en produktionslösning för lösenord.
Skapa en tom övningsmapp. Du behöver Node.js, npm och installerad Google Chrome. Provet använder den versionslåsta Playwright Test-version som körts för den här guiden. Valet channel: 'chrome' följer dokumentationen om browser channels. Lägg först in beroendet:
npm init -y
npm install --save-dev @playwright/test@1.58.2
Spara servern som server.cjs. Kontot heter demo och lösenordet lokalt-prov. Dessa värden gäller enbart övningen. Servern lyssnar på loopback-adressen, och varje korrekt inloggning ger en slumpad sessionsidentifierare. Kontosidan läser identifieraren ur cookien och slår upp den i minnet. Om servern startas om finns den gamla identifieraren inte längre kvar.
const http = require('node:http');
const { randomUUID } = require('node:crypto');
const sessions = new Set();
const login = `<!doctype html><html lang="sv"><meta charset="utf-8">
<title>Lokalt inloggningsprov</title><h1>Logga in</h1>
<form action="/login" method="post">
<label>Användare <input name="user" required></label>
<label>Lösenord <input name="password" type="password" required></label>
<button>Logga in</button></form></html>`;
http.createServer(async (req, res) => {
const html = text => {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(text);
};
if (req.url === '/login' && req.method === 'POST') {
let body = '';
for await (const chunk of req) body += chunk;
const form = new URLSearchParams(body);
if (form.get('user') !== 'demo' || form.get('password') !== 'lokalt-prov') {
res.writeHead(401); res.end('Fel testkonto'); return;
}
const token = randomUUID();
sessions.add(token);
res.writeHead(303, {
Location: '/account',
'Set-Cookie': `sid=${token}; HttpOnly; SameSite=Lax; Path=/`
});
res.end(); return;
}
if (req.url === '/account') {
const token = (req.headers.cookie || '').split('; ')
.find(value => value.startsWith('sid='))?.slice(4);
if (!sessions.has(token)) {
res.writeHead(303, { Location: '/login' }); res.end(); return;
}
html('<!doctype html><html lang="sv"><meta charset="utf-8"><title>Konto</title><h1>Inloggad som demo</h1><p>Projekt: Lokalt läsprov</p></html>');
return;
}
if (req.url === '/' || req.url === '/login') { html(login); return; }
res.writeHead(404); res.end();
}).listen(4186, '127.0.0.1');
Servern saknar bland annat produktionsanpassad lösenordslagring, HTTPS och skydd mot upprepade inloggningsförsök. Använd den som lokal testfixture. Byt inte ut demo mot ett riktigt konto för att göra övningen mer realistisk. Om port 4186 är upptagen väljer du en annan port i server, konfiguration och ogiltighetstestet nedan.
2. Ignorera sessionsfiler innan du skapar dem
Skapa .gitignore innan första körningen. Playwrights autentiseringsguide varnar för att sparat tillstånd kan innehålla känsliga cookies och andra uppgifter som kan ge tillgång till testkontot. Använd därför en ignorerad katalog även i denna syntetiska övning. Lägg inte filinnehållet i HTML, Git, felrapporter eller en prompt till en kodassistent.
node_modules/
playwright/.auth/
test-results/
playwright-report/
Enligt Git-referensen för gitignore påverkar reglerna inte redan spårade filer. Om en sessionsfil redan är spårad hjälper regeln alltså inte som städning av den befintliga historiken. Kontrollera vad du faktiskt har lagt till före en commit. För guidens rena övningsmapp ska sessionsfilen skapas först efter att regeln finns. Det är katalogens plats och hantering du återanvänder i ett riktigt projekt, inte kontouppgifterna.
3. Verifiera inloggningen och spara storageState
Skapa katalogen tests och spara följande som tests/auth.setup.ts. Setup fyller formuläret, inväntar adressen /account och kontots synliga rubrik. Först därefter skrivs filen. Den ordningen följer autentiseringsguidens exempel: spara efter att inloggningen nått ett verifierbart tillstånd, inte direkt efter ett klick.
import { test as setup, expect } from '@playwright/test';
import { mkdir } from 'node:fs/promises';
setup('spara verifierad inloggning', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Användare').fill('demo');
await page.getByLabel('Lösenord').fill('lokalt-prov');
await page.getByRole('button', { name: 'Logga in' }).click();
await expect(page).toHaveURL('/account');
await expect(page.getByRole('heading', { name: 'Inloggad som demo' })).toBeVisible();
await mkdir('playwright/.auth', { recursive: true });
await page.context().storageState({ path: 'playwright/.auth/user.json' });
});
Välj ett kvitto som passar din egen app när du anpassar provet. En knapp kan ha klickats trots att formuläret sedan visar fel. En adress kan dessutom nås innan appen hunnit läsa färdigt sin användare. Kombinationen av slutlig URL och en kontospecifik rubrik gör just övningens kvitto tydligt. Spara inte tillståndet från felmeddelandesidan för att få nästa test att börja snabbare.
4. Gör setup till projektberoende
Spara playwright.config.ts i övningsmappen. Här startar webServer-inställningen den lokala servern inför testkörningen. Den accepterar inte en redan startad server: provet ska använda sin egen kända fixture. Kör därför inte en extra server manuellt samtidigt.
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './tests',
retries: 0,
workers: 1,
use: {
baseURL: 'http://127.0.0.1:4186',
browserName: 'chromium', channel: 'chrome'
},
webServer: {
command: 'node server.cjs',
url: 'http://127.0.0.1:4186/login',
reuseExistingServer: false
},
projects: [
{ name: 'setup', testMatch: '**/auth.setup.ts' },
{
name: 'authenticated', testMatch: '**/account.spec.ts',
dependencies: ['setup'],
use: { storageState: 'playwright/.auth/user.json' }
},
{
name: 'anonymous', testMatch: '**/anonymous.spec.ts',
use: { storageState: { cookies: [], origins: [] } }
}
]
});
Enligt dokumentationen om projektberoenden körs setup före projekten som beror på det. Misslyckas setup körs inte dess beroende tester. I vårt exempel får authenticated filen som storageState, medan anonymous uttryckligen använder tomma cookies och origins. Filtreringen håller setup, läsprov och kontrollprov åtskilda. Undvik flaggan --no-deps här eftersom den hoppar över beroenden.
5. Kör ett skyddat lästest och två kontrollprov
Spara lästestet som tests/account.spec.ts. Det fyller inget formulär. Testets page-fixture får en ny browser context med det sparade tillståndet och navigerar direkt till den skyddade sidan. Facit är både kontorubriken och den syntetiska projekttexten. Därmed visar provet att sessionen fungerar efter setup, i stället för att bara bekräfta att setup lyckades på sin egen sida.
import { test, expect } from '@playwright/test';
test('ny context kan läsa kontot med sparat tillstånd', async ({ page }) => {
await page.goto('/account');
await expect(page).toHaveURL('/account');
await expect(page.getByRole('heading', { name: 'Inloggad som demo' })).toBeVisible();
await expect(page.getByText('Projekt: Lokalt läsprov', { exact: true })).toBeVisible();
});
Spara kontrollproven som tests/anonymous.spec.ts. Det första provar samma adress utan session. Det andra lägger in en avsiktligt okänd sessionsidentifierare. Båda ska hamna på inloggningssidan och sakna projekttexten. Ett test som bara kontrollerar att sidan laddar skulle missa att den skyddade vyn råkar visas för en utloggad besökare.
import { test, expect } from '@playwright/test';
test('utan sparad session visas inloggning', async ({ page }) => {
await page.goto('/account');
await expect(page).toHaveURL('/login');
await expect(page.getByRole('heading', { name: 'Logga in' })).toBeVisible();
await expect(page.getByText('Projekt: Lokalt läsprov', { exact: true })).toHaveCount(0);
});
test('ogiltig session släpper inte in', async ({ context, page }) => {
await context.addCookies([{
name: 'sid', value: 'avsiktligt-ogiltig',
url: 'http://127.0.0.1:4186', httpOnly: true, sameSite: 'Lax'
}]);
await page.goto('/account');
await expect(page).toHaveURL('/login');
await expect(page.getByRole('heading', { name: 'Logga in' })).toBeVisible();
await expect(page.getByText('Projekt: Lokalt läsprov', { exact: true })).toHaveCount(0);
});
Kör från övningsmappen med följande kommando. Förväntat resultat är fyra passerade tester: ett setup-test, ett lästest och två kontrollprov. Inställningen workers: 1 gör provets körning enkel att följa; den ska inte tolkas som ett krav på alla framtida testsviter.
npx playwright test --reporter=line
| Prov | Synligt facit |
|---|---|
| Sparad session | /account, Inloggad som demo och Projekt: Lokalt läsprov. |
| Tom lagring | /login, Logga in och ingen projekttext. |
| Okänd session | Samma utloggade resultat; cookiens existens räcker inte. |
De fyra testerna kördes lokalt den 15 oktober 2026 på Windows med Node.js 24.13.0, Playwright Test 1.58.2 och installerad Chrome. Samtliga passerade. Körningen använde exakt filerna i guiden och syntetiskt sessionsinnehåll. Resultatet gäller övningens cookiebaserade app; det verifierar ingen extern inloggning, IndexedDB-integration eller produktionsmiljö.
6. Förnya tillståndet och skilj på lagringstyper
Den normala körningen loggar in på nytt och skriver över filen. Det behövs i denna app eftersom sessionerna bara lever så länge serverprocessen kör. Om ditt riktiga testkonto har fått sin session återkallad eller för gammal ska du återskapa tillståndet genom inloggningen. Ändra inte det skyddade testets förväntan till att godta inloggningssidan. Kör bara det beroende projektet så följer setup med:
npx playwright test --project=authenticated --reporter=line
Ogiltighetstestet ovan simulerar en okänd identifierare. Det mäter inte hur lång tid en verklig session gäller eller hur en leverantör förnyar token. För ett verkligt utgångsflöde behöver du ett kontrollerat sätt att återkalla sessionen i testmiljön. Guidens lilla server har ingen sådan administrationsfunktion.
| Lagring | Val i detta upplägg |
|---|---|
| Cookies | Ingår i storageState. Det är den mekanism som faktiskt körs här. |
| localStorage | Ingår också i storageState. Kontrollera appens egen lagring och rätt origin. |
| IndexedDB | Begär snapshot med indexedDB: true om autentiseringen ligger där. |
| sessionStorage | Följer inte med via storageState; kräver separat export och återställning. |
Om din app använder IndexedDB visar API-referensen för storageState det uttryckliga alternativet. Byt då sparraden till varianten nedan. Det är ett dokumenterat API-val; den här guidens körprov verifierar ingen IndexedDB-baserad inloggning.
await page.context().storageState({
path: 'playwright/.auth/user.json', indexedDB: true
});
För sessionStorage beskriver autentiseringsguiden en separat lösning med export och addInitScript i den nya contexten, avgränsad till rätt värd. Kopiera inte det upplägget utan att först kontrollera var din app faktiskt sparar sitt tillstånd. Att en JSON-fil finns på disk bevisar inte att den innehåller appens inloggning.
7. Byt upplägg när tester skriver serverdata
Vårt skyddade test läser en fast projekttext. För tester som ändrar samma serverdata rekommenderar autentiseringsguiden separata konton per parallell worker. Tänk dig att ett test byter visningsnamn medan ett annat förväntar sig det tidigare namnet. Två isolerade browser contexts löser inte att båda kontona pekar på samma användarrad.
Ordna separata syntetiska konton och testdata innan du parallelliserar sådana skrivtester. Skapa tillstånd per konto och koppla rätt fil till rätt worker. Om flera utvecklare eller CI-körningar använder samma testmiljö behöver kontofördelningen också skilja deras samtidiga körningar åt. Att bara kopiera samma sessionsfil till fler filnamn ger inte separata konton.
Behåll denna guide för setup och återanvänd autentisering. För bestämda nätverkssvar fortsätter du till mocka API i Playwright. För att undersöka ett misslyckat inloggningssteg finns Playwright Trace Viewer. Använd testningsguiden när du väljer vilka övriga flöden appen behöver.
Källor och avgränsning
- Playwright: Authentication – återanvänd autentisering, säker filhantering och kontofördelning.
- Playwright: BrowserContext.storageState – lagring och IndexedDB-val.
- Playwright: Projects – beroenden och filtrering.
- Playwright: Web server – lokal testserver.
- Playwright: Browsers – installerad Chrome.
Primärkällorna kontrollerades 15 oktober 2026. App, testkonto och facit är egna lokala exempel. Ingen verklig användare eller tjänst testas.