diff --git a/_playwright-tests/test-utils/src/fixtures/client.ts b/_playwright-tests/test-utils/src/fixtures/client.ts index c3054e245..61105b148 100644 --- a/_playwright-tests/test-utils/src/fixtures/client.ts +++ b/_playwright-tests/test-utils/src/fixtures/client.ts @@ -1,38 +1,77 @@ // Define a fixture to hold the API client -import { test as oldTest, expect } from '@playwright/test'; -import { Configuration, ResponseContext, ResponseError } from '../client'; -import { setGlobalDispatcher, ProxyAgent, Agent } from 'undici'; +import { test as oldTest, expect, APIRequestContext, APIResponse } from '@playwright/test'; +import { Configuration, ResponseError, FetchAPI } from '../client'; +import { fileNameToEnvVar, getFileNameFromAuthPath } from 'test-utils/helpers'; type WithApiConfig = { client: Configuration; }; -// Default error handling doesn't print the error, so print it here -const responseReader = { - post: async function (context: ResponseContext): Promise { - if (context.response != undefined && context.response.status > 300) { - const bodyText = await context.response.text(); - console.log('Response errored with ' + context.response.status + ': ' + bodyText); +function isString(value: unknown): value is string { + return typeof value === 'string'; +} + +function constructHeaders(headers?: HeadersInit, storageState?: string, extraHTTPHeaders?: {[key: string]: string}) { + const out: Record = {}; + + if (storageState) { + const tokenName = fileNameToEnvVar(getFileNameFromAuthPath(storageState)); + const token = process.env[tokenName]; + if (!token) { + throw new Error( + `Token environment variable "${tokenName}" is not set. Check authentication setup.`, + ); } - }, -}; + out['authorization'] = token; + } else if (extraHTTPHeaders) { + new Headers(extraHTTPHeaders).forEach((value, key) => { out[key] = value; }); + } + + if (headers) { + new Headers(headers).forEach((value, key) => { out[key] = value; }); + }; + + return Object.keys(out).length ? out : undefined; +} + +async function toFetchResponseBody( + response: APIResponse, +): Promise { + const nullBodyResponses = new Set([101, 103, 204, 205, 304]); + if (nullBodyResponses.has(response.status())) return undefined; + + return response.body().then((b) => b.toString()); +} export const clientTest = oldTest.extend({ client: - // eslint-disable-next-line no-empty-pattern - async ({ extraHTTPHeaders }, use, r) => { - if (r.project?.use?.proxy?.server) { - const dispatcher = new ProxyAgent({ uri: new URL(r.project.use.proxy.server).toString() }); - setGlobalDispatcher(dispatcher); - } else if (r.project.use.baseURL?.match('^https:\/\/\\w+\.foo\.redhat\.com:\\d+$')?.length) { - const dispatcher = new Agent({ connect: { rejectUnauthorized: false } }); - setGlobalDispatcher(dispatcher); - } + async ({ extraHTTPHeaders, request, storageState }, use, r) => { + const pwFetch = (api: APIRequestContext): FetchAPI => async (url, init) => { + const storage = storageState ?? r.project.use.storageState; + const extraHeaders = extraHTTPHeaders ?? r.project.use.extraHTTPHeaders; + const response = await api.fetch(String(url), { + failOnStatusCode: false, + ignoreHTTPSErrors: true, + method: init?.method, + headers: constructHeaders(init?.headers, isString(storage) ? storage : undefined, extraHeaders), + data: init?.body, + }); + + try { + return new Response(await toFetchResponseBody(response), { + status: response.status(), + statusText: response.statusText(), + headers: response.headers(), + }); + } finally { + await response.dispose(); + } + }; const client = new Configuration({ + fetchApi: pwFetch(request), basePath: r.project.use.baseURL + '/api/content-sources/v1', - headers: extraHTTPHeaders ?? r.project.use.extraHTTPHeaders, - middleware: [responseReader], + middleware: [], }); await use(client); diff --git a/_playwright-tests/test-utils/src/helpers/poll.ts b/_playwright-tests/test-utils/src/helpers/poll.ts index 708f0fd4c..8b8903bff 100644 --- a/_playwright-tests/test-utils/src/helpers/poll.ts +++ b/_playwright-tests/test-utils/src/helpers/poll.ts @@ -29,12 +29,12 @@ export const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms)); * Waits for a repository introspection to complete by polling the repository status. * @param client - Configuration object for API client * @param repoUuid - UUID of the repository to check - * @param interval - Polling interval in seconds (default: 10) + * @param interval - Polling interval in miliseconds (default: 200) */ export const waitWhileRepositoryIsPending = async ( client: Configuration, repoUuid: string, - interval: number = 10, + interval: number = 200, ): Promise => { const getRepository = () => new RepositoriesApi(client).getRepository({ diff --git a/_playwright-tests/tests/API/Repositories.spec.ts b/_playwright-tests/tests/API/Repositories.spec.ts index 2dabd2ad6..d2d9b39da 100644 --- a/_playwright-tests/tests/API/Repositories.spec.ts +++ b/_playwright-tests/tests/API/Repositories.spec.ts @@ -44,7 +44,7 @@ test.describe('Repositories', () => { }); await test.step('Wait for introspection to be completed', async () => { - const resp = await waitWhileRepositoryIsPending(client, repo.uuid!.toString()); + const resp = await waitWhileRepositoryIsPending(client, repo.uuid!.toString(), 50); expect(resp.status).toBe('Valid'); expect(resp.lastIntrospectionTime).toBeDefined(); diff --git a/_playwright-tests/tests/auth.setup.ts b/_playwright-tests/tests/auth.setup.ts index e52979e78..bc0ded367 100644 --- a/_playwright-tests/tests/auth.setup.ts +++ b/_playwright-tests/tests/auth.setup.ts @@ -1,11 +1,10 @@ import { expect, test as setup } from '@playwright/test'; import { setAuthorizationHeader, throwIfMissingEnvVariables } from './helpers/loginHelpers'; -import { describe } from 'node:test'; const DefaultOrg = 99999; const DefaultUser = 'BananaMan'; -describe('Setup', async () => { +setup.describe('Setup', async () => { setup('Ensure needed ENV variables exist', async () => { expect(() => throwIfMissingEnvVariables()).not.toThrow(); }); diff --git a/playwright.config.ts b/playwright.config.ts index 02a861b9a..d02673931 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -3,7 +3,7 @@ import path from 'path'; import { config } from 'dotenv'; -config({ path: path.join(__dirname, './.env') }); +config({ path: path.join(__dirname, './.env'), quiet: true }); // test-utils storageState paths; respect PLAYWRIGHT_AUTH_DIR when set (CI or local). if (!process.env.PLAYWRIGHT_AUTH_DIR) { @@ -48,7 +48,7 @@ export default defineConfig({ projects: [ { name: 'setup', testMatch: /.*\.setup\.ts/, expect: { timeout: 20000 } }, { - name: 'Google Chrome', + name: 'API', use: { ...devices['Desktop Chrome'], },