microsoft / playwright

Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://playwright.dev
Apache License 2.0
66.45k stars 3.63k forks source link

[BUG] Clipboard API, ClipboardItem not working in headless (chromium) #24039

Open gustav-larsson opened 1 year ago

gustav-larsson commented 1 year ago

System info

or

Config file

// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
import * as puppeteer from 'puppeteer';
const whiteListDomains = '*scania.com';
const chromiumFlags = [
    '--auth-negotiate-delegate-whitelist='+whiteListDomains,
    '--auth-schemes="basic,ntlm,negotiate"',
    '--auth-server-allowlist='+whiteListDomains,
    /**
     * @deprecated will be removed in future chromium versions
     */
    '--auth-server-whitelist='+whiteListDomains,
    '--disable-dev-shm-usage',
    '--disable-extensions',
    '--disable-setuid-sandbox',
    '--no-sandbox',
    '--window-size=1920,1200'
];
/**
 * See https://playwright.dev/docs/test-configuration.
 */
const config: PlaywrightTestConfig = {
    //testMatch: /.*(e2e-spec)\.(js|ts|mjs)/,
    testMatch: '**/*.e2e-spec.ts',
    testIgnore: ['**/productcoord1.e2e-spec.ts**', '**/copy.paste.e2e-spec.ts'],
    /* Maximum time one test can run for. */
    timeout: process.env.CI ? 120 * 1000 : 60 * 1000,

    globalSetup: './playwright.setup.ts',
    expect: {
        /**
         * Maximum time expect() should wait for the condition to be met.
         * For example in `await expect(locator).toHaveText();`
         */
        timeout: process.env.CI ? 15 * 1000 : 10 * 1000
    },
    /* Run tests in files in parallel */
    fullyParallel: true,
    /* Fail the build on CI if you accidentally left test.only in the source code. */
    forbidOnly: !!process.env.CI,
    /* Retry on CI only */
    retries: process.env.CI ? 2 : 0,
    /* Opt out of parallel tests on CI. */
    workers: process.env.CI ? 30 : 4,
    /* Reporter to use. See https://playwright.dev/docs/test-reporters */

    reporter: process.env.CI ? [
        ['list'],
        ['../internal-lib-e2e/src/reporters/rerun-reporter'],
        ['html', { outputFolder: '.test_results/'+ process.env.SUITE }],
        ['../internal-lib-e2e/src/reporters/rerun-reporter']
    ] : [
        ['list'],
        ['html', { outputFolder: '.test_results/test_report' }]
    ],
    /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
    use: {
        actionTimeout: 0,
        trace: process.env.CI ? 'retain-on-failure' : 'on',
        screenshot: process.env.CI ? 'only-on-failure' : 'on',
        video: process.env.CI ? 'retain-on-failure' : 'on',
        viewport: null
    },
    /* Configure projects for major browsers */
    projects: [
        {
            name: 'full',
            use: {
                browserName: 'chromium',
                permissions: ['clipboard-read', 'clipboard-write'],
                contextOptions: {
                    permissions: ['clipboard-read', 'clipboard-write']
                },
                launchOptions: {
                    args: chromiumFlags,
                    executablePath: undefined
                }
            }
        },
        {
            name: 'auth',
            testMatch: '**/productcoord1.e2e-spec.ts',
            testIgnore: '',
            use: {
                browserName: 'chromium',
                permissions: ['clipboard-read', 'clipboard-write'],
                contextOptions: {
                    permissions: ['clipboard-read', 'clipboard-write']
                },
                launchOptions: {
                    args: chromiumFlags,
                    executablePath: undefined
                }
            }
        },
        {
            name: 'copy',
            testMatch: '**/copy.paste.e2e-spec.ts',
            testIgnore: '',
            use: {
                browserName: 'chromium',
                permissions: ['clipboard-read', 'clipboard-write'],
                contextOptions: {
                    permissions: ['clipboard-read', 'clipboard-write']
                },
                launchOptions: {
                    args: chromiumFlags,
                    executablePath: process.env.CI ? puppeteer.executablePath() : undefined
                }
            }
        }
    ],
    outputDir: '.test_results/output'
};

export default config;

Steps

Expected

[I expect to have the ClipboardItem in my clipboard instead of the raw text]

Actual

[I get the raw text]

This works in headed Playwright Chromium and headless puppeteer Chromium 107

lampewebdev commented 1 year ago

I have run into the same issue and I can add a small repo later.

sortegam commented 11 months ago

+1

showonne commented 9 months ago

mark, I write a simple util function:

export const writeTextToClipboard = async (page, text) => {
  await page.evaluate((text) => {
    if (navigator.clipboard) {

      // Write the URL to the clipboard
      navigator.clipboard.writeText(text)
        .then((resp) => {
          console.log('eval done', resp)
        })
        .catch(err => {
          console.error('Error copying to clipboard:', err);
        });
    } else {
      // Fallback for browsers that do not support the Clipboard API
      console.warn('Clipboard API not supported in this browser');
    }
  }, [text])
}

It works in headed browser but not work in headless browser (uncheck 'Show browser' option in VSCode plugun)

haveneersrobin commented 8 months ago

It seems that cutting in headless mode only allows to do navigator.clipboard.readText() and not .read(). Our workaround is to check if there is type on the clipboard item, if not, resort to readText()