I am trying to use Playwright to carry out an API test. The simple case is that I am trying to get info on a user. To do this with curl, I can issue the command:
curl --user username:password https://example.com/api/user/id
This will respond with some JSON.
I have read through the Playwright docs, watched some YouTube videos and scoured various sources, but can't find out how to replicate this in Playwright.
My requests are consistently getting a response of "403 Forbidden".
In my playwright.config.ts file, I have added httpCredentials like so:
import type { PlaywrightTestConfig } from '@playwright/test';
import { devices } from '@playwright/test';
const config: PlaywrightTestConfig = {
[...]
use: {
headless: false,
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
actionTimeout: 0,
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: 'https://example.com',
httpCredentials: {
username: 'username',
password: 'password'
},
[...]
Meanwhile, in my apiExperiment.spec.ts file:
import {test} from '@playwright/test';
test.describe('Test the API', () => {
test('Get user info', async({request}) => {
let userInfo = await request.post('/api/user/id');
});
});
As I said previously, this just results in "403 Forbidden".
I have tried variations on this theme, like removing the httpCredentials from the config file, then changing the apiExperiment.spec.ts file to:
import {test} from '@playwright/test';
test.describe('Test the API', () => {
test('Get user info', async({request}) => {
let userInfo = await request.post('/api/user/id', {
data: {
username: 'username',
password: 'password',
}
});
});
});
and another variation:
import {test} from '@playwright/test';
test.describe('Test the API', () => {
test('Get user info', async({request, browser}) => {
const context = await browser.newContext({
httpCredentials: {username: 'username', password: 'password'}
});
let userInfo = await context.request.post('/api/user/id');
});
});
but to no avail.
After some extensive digging around, I managed to resolve this. The issue is that apparently if you use httpCredentials, Playwright will make a request omitting the Authorization header. It then expects a 401 status code in the response and, if it gets that, will repeat the request with the credentials specified in the header.
This behaviour is a problem for me, as a request without credentials results in a response code of 403.
Before talking about the fix that I applied, I should add the caveat that it may not be suitable in all cases - I made changes in the config file as I wanted the Authorization header to be used throughout my tests. Also, I'm sure there are more secure/preferred ways of storing the username and password than hard-coding them into a config file, but my concern here was to get something working.
Bearing in mind those caveats, the way I got this working was to encode the username and password and manually define the Authorization header in playwright.config.ts:
import type { PlaywrightTestConfig } from '@playwright/test';
import { devices } from '@playwright/test';
const httpCredentials = {
username: 'username',
password: 'password',
};
const btoa = (str: string) => Buffer.from(str).toString('base64');
const credentialsBase64 = btoa(`${httpCredentials.username}:${httpCredentials.password}`);
const config: PlaywrightTestConfig = {
// ...
use: {
// ...
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: 'https://example.com',
extraHTTPHeaders: {
'Authorization': `Basic ${credentialsBase64}`
},
// ...
};
Following this, the Authorization header is added to every call to the server and everything works as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With