Search code examples
playwright-test

How to set the `Accept-Language` header for one test in Playwright?


How can I set the Accept-Language header for one test call in Playwright ?

E.g.:

import { test, expect } from '@playwright/test';

test( 'language is interpreted correctly', async function({ page, context }) {

    // -----
    // HERE: Set the `Accept-Language` header to 'de-DE,de;q=0.9,en;q=0.8' somehow ?
    // -----
    
    const response = await page.goto( 'http://example.com' );
    const acceptLanguageHeader = await response.request().headerValue('Accept-Language');
    expect( acceptLanguageHeader ).toBe( 'de-DE,de;q=0.9,en;q=0.8' );
    expect( somethingThatDependsOnTheLanguage ).toBe( true );
});

What I found, which doesn't work:

I know I can set extra headers with page.setExtraHTTPHeaders(), but that apparently doesn't overwrite the Accept-Language header.

I know I can configure TestOptions with:

but I want to test different settings in each test() call.

E.g. this doesn't work:

test( 'try modified accept-language header', async function({ page, context }) {

    await context.setExtraHTTPHeaders({
        'Accept-Language': 'de-DE,de;q=0.9,en;q=0.8',
        'some-extra-header': 'some extra header value from context',
    });

    await page.setExtraHTTPHeaders({
        'Accept-Language': 'de-DE,de;q=0.9,en;q=0.8',
        'some-extra-header': 'some extra header value from page',
    });

    const response = await page.goto( 'http://example.com' );

    console.log('headers:', response.request().headers()); // <-- 'accept-language' is 'en-US',

    const acceptLanguageHeader = await response.request().headerValue('Accept-Language');
    expect( acceptLanguageHeader ).toBe( 'de-DE,de;q=0.9,en;q=0.8' ); // <-- Received: "en-US"
});

I have seen the answers to "How to add custom headers ..." and "How to change default language ..." and other examples, but

  • they are creating their own browser and browser.context (like const context = await browser.newContext( ... )), and
  • they are not using a test call, and
  • don't show where they get the browser instance from.
  • (Probably they are not using the playwright test-runner. I don't know how they are running their tests)

Solution

  • You can use browserContext.route() to modify network requests in each test individually.

    E.g.:

    test( 'Example for browserContext.route()', async function({ page, context }) {
    
        // -- modify the request
        await context.route('**/*', (route, request) => {
            route.continue({
                headers: {
                    ...request.headers(),
                    'accept-language': 'de-DE,de;q=0.9,en;q=0.8',
                }
            });
        });
    
        // -- navigate
        await page.goto( urlOfMyWebsite );
        
        // -- test if language of accept-header is correctly used
        expect( someContent ).toBe( translatedToGerman );
    });
    

    RegExp is also allowed to match the url, e.g.:

    await context.route(/^\/[-a-z]+$/, (route, request) => { ...
    

    Note that the header name seems to be case-sensitive, and might behave weird. I found different tests behave in different ways, for example (I could not always reproduce this in different environments):

    • setting only 'Accept-Language': 'de-DE' might result in e.g. Received: "en-US, de-DE".
    • setting both: 'Accept-Language': 'de-DE', 'accept-language': 'de-DE' might result in Received: "de-DE, de-DE".