If you’re still writing login steps in every single Playwright test file, you’re slowing yourself down.
Instead of wasting time on repeated UI logins, you can log in programmatically via API and reuse that session in all your tests.
In this guide, you’ll learn how to turn an API login helper into a reusable Playwright fixture — speeding up your end-to-end tests while keeping them stable.
If you’re still writing login steps in every single test file, you’re wasting time.
Let me show you how to go from UI login:
await page.goto('/login');
await page.fill('#email', 'user@test.com');
await page.fill('#password', 'DontTestMe');
await page.click('button[type="submit"]');
To this:
await apiLogin(page, request, adminEmail, adminPassword);
await page.goto('/dashboard');
And finally, to this:
await authenticatedPage.goto('/dashboard');
No UI login. No wasted time. Just results.
The Setup: API Login via Token
Let’s say your backend gives you an accessToken after
a POST to /api/users/login. We’ll use that to inject the cookie directly.
This trick will log in your user programmatically before the test even starts.
Step 1: Your apiLogin.js helper
Create this file:
// Send login api request
const apiResponse = await apiClient.post(/api/users/login
, {
data: {
email,
password
}
});
// Convert response to json
const apiResponseJson = await apiResponse.json();
// Return accessToken for future usage
return apiResponseJson.accessToken;
}
Step 2: Create a Playwright fixture
Create this file:
import { apiLogin } from ‘../api/UsersApi’;
export const test = base.extend({
authenticatedPage: async ({ browser }, use) => {
// Step 1: Create an API client (apiContext)
const apiClient = await request.newContext();
// Step 2: Send api login request
const token = await apiLogin(apiClient, ‘test@gmail.com’, ‘12345678’);
// Step 3: Create a browser context to add your apiToken to
const context = await browser.newContext();
// Step 4: Inject localStorage token before any page is created
await context.addInitScript((tokenValue) => {
window.localStorage.setItem(‘accessToken’, tokenValue);
}, token);
// Step 5: Create and use new page our of context above
const page = await context.newPage();
await use(page);
await context.close();
}
});
Step 3: Write your test
test(‘should find best qa automation bootcamp’, async ({ authenticatedPage, createdListing }) => {
await authenticatedPage.goto(‘https://www.youtube.com/@Codemify’);
await expect(authenticatedPage).toHaveText(/Best QA Bootcamp/);
});
Why This Is So Powerful
- Speed – No need to visit login page, wait for form, or click buttons.
- Stability – Removes flaky UI interactions from critical path.
- Reusability – You can now use authenticated Page anywhere.
And let’s be honest — if you’re going to scale your tests or teach others how to automate, this is the standard.
_”Use real user flows in your app once, then move all auth to the backend. You should test your login UI once — but run your actual tests with blazing-fast, headless tokens.
Automation is about speed and precision, not repeating what a human would do”_
— Sergii
Founder of Codemify
Follow us on YouTube |