From 661fd29a5e10c68378af765f38f346fd524e4976 Mon Sep 17 00:00:00 2001 From: Gianluca Zuccarelli Date: Wed, 23 Jul 2025 10:43:11 +0100 Subject: [PATCH] playwright: add timeout for cockpit tests Playwright at times is making assertions before the osbuild-worker file is loaded. This is causing some flakiness in the tests, adding a timeout before some of the assertions should hopefully remove some of the flakiness. --- playwright/test.spec.ts | 32 ++++++++++++------- .../CloudProviderConfig/AWSConfig.tsx | 15 ++++++--- .../CloudProviderConfig.tsx | 16 ++++++++-- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/playwright/test.spec.ts b/playwright/test.spec.ts index 86572a17..0f46028e 100644 --- a/playwright/test.spec.ts +++ b/playwright/test.spec.ts @@ -87,7 +87,7 @@ test.describe.serial('test', () => { await frame.getByRole('button', { name: 'Create blueprint' }).click(); await expect( - frame.locator('.pf-v6-c-card__title-text').getByText(blueprintName) + frame.locator('.pf-v6-c-card__title-text').getByText(blueprintName), ).toBeVisible(); }); @@ -196,14 +196,16 @@ test.describe.serial('test', () => { const switchInput = frame.locator('#aws-config-switch'); await expect(switchInput).toBeVisible(); - // the test is a little bit flaky, if it fails the first time - // while setting the configs, the second time the config should - // already be loaded and visible, if it is go back to the landing page - // https://github.com/osbuild/image-builder-frontend/issues/3429 + // introduce a wait time, since it takes some time to load the + // worker config file. + await page.waitForTimeout(1000); + + // If this test fails for any reason, the config should already be loaded + // and visible on the retury. If it is go back to the landing page if (await switchInput.isChecked()) { await frame.getByRole('button', { name: 'Cancel' }).click(); await expect( - frame.getByRole('heading', { name: 'All images' }) + frame.getByRole('heading', { name: 'All images' }), ).toBeVisible(); } else { const switchToggle = frame.locator('.pf-v6-c-switch'); @@ -217,7 +219,7 @@ test.describe.serial('test', () => { await frame.getByPlaceholder('Path to AWS credentials').fill(credentials); await frame.getByRole('button', { name: 'Submit' }).click(); await expect( - frame.getByRole('heading', { name: 'All images' }) + frame.getByRole('heading', { name: 'All images' }), ).toBeVisible(); } @@ -225,6 +227,11 @@ test.describe.serial('test', () => { .getByRole('button', { name: 'Configure Cloud Providers' }) .click(); await expect(header).toBeVisible(); + + // introduce a wait time, since it takes some time to load the + // worker config file. + await page.waitForTimeout(1500); + await expect(frame.locator('#aws-config-switch')).toBeChecked(); await expect(frame.getByPlaceholder('AWS bucket')).toHaveValue(bucket); @@ -241,6 +248,7 @@ test.describe.serial('test', () => { expect(parsed.aws?.credentials).toBe(credentials); }); + const cockpitBlueprintname = uuidv4(); test('cockpit cloud upload', async ({ page }) => { if (isHosted()) { return; @@ -266,8 +274,10 @@ test.describe.serial('test', () => { await frame.getByRole('button', { name: 'Back', exact: true }).click(); frame.getByRole('heading', { name: 'Details' }); - await frame.getByTestId('blueprint').fill(blueprintName); - await expect(frame.getByTestId('blueprint')).toHaveValue(blueprintName); + await frame.getByTestId('blueprint').fill(cockpitBlueprintname); + await expect(frame.getByTestId('blueprint')).toHaveValue( + cockpitBlueprintname, + ); await frame.getByRole('button', { name: 'Next', exact: true }).click(); await frame.getByRole('button', { name: 'Create blueprint' }).click(); @@ -276,10 +286,10 @@ test.describe.serial('test', () => { await frame .getByRole('textbox', { name: 'Search input' }) - .fill(blueprintName); + .fill(cockpitBlueprintname); // the clickable blueprint cards are a bit awkward, so use the // button's id instead - await frame.locator(`button[id="${blueprintName}"]`).click(); + await frame.locator(`button[id="${cockpitBlueprintname}"]`).click(); await frame.getByTestId('blueprint-build-image-menu-option').click(); // make sure the image is present diff --git a/src/Components/CloudProviderConfig/AWSConfig.tsx b/src/Components/CloudProviderConfig/AWSConfig.tsx index 1051767a..076ccc5f 100644 --- a/src/Components/CloudProviderConfig/AWSConfig.tsx +++ b/src/Components/CloudProviderConfig/AWSConfig.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { Button, @@ -38,7 +38,7 @@ type ToggleGroupProps = Omit, 'isDisabled'>; const AWSConfigToggle = ({ value, onChange }: ToggleGroupProps) => { const handleChange = ( _event: React.FormEvent, - checked: boolean + checked: boolean, ) => { onChange(checked); }; @@ -159,18 +159,23 @@ const AWSCredsPath = ({ }; type AWSConfigProps = { - isEnabled: boolean; + enabled: boolean; + setEnabled: (enabled: boolean) => void; reinit: (config: AWSWorkerConfig | undefined) => void; refetch: () => Promise<{ data?: WorkerConfigResponse | undefined; }>; }; -export const AWSConfig = ({ isEnabled, refetch, reinit }: AWSConfigProps) => { +export const AWSConfig = ({ + enabled, + setEnabled, + refetch, + reinit, +}: AWSConfigProps) => { const dispatch = useAppDispatch(); const bucket = useAppSelector(selectAWSBucketName); const credentials = useAppSelector(selectAWSCredsPath); - const [enabled, setEnabled] = useState(isEnabled); const onToggle = async (v: boolean) => { if (v) { diff --git a/src/Components/CloudProviderConfig/CloudProviderConfig.tsx b/src/Components/CloudProviderConfig/CloudProviderConfig.tsx index e5897a09..ed5523a4 100644 --- a/src/Components/CloudProviderConfig/CloudProviderConfig.tsx +++ b/src/Components/CloudProviderConfig/CloudProviderConfig.tsx @@ -1,4 +1,9 @@ -import React, { MouseEventHandler, useCallback, useEffect } from 'react'; +import React, { + MouseEventHandler, + useCallback, + useEffect, + useState, +} from 'react'; import { Button, @@ -68,6 +73,7 @@ export const CloudProviderConfig = () => { const dispatch = useAppDispatch(); const config = useAppSelector(selectAWSConfig); const handleClose = () => navigate(resolveRelPath('')); + const [enabled, setEnabled] = useState(false); const [updateConfig] = useUpdateWorkerConfigMutation(); const { data, error, refetch, isLoading } = useGetWorkerConfigQuery({}); @@ -76,9 +82,12 @@ export const CloudProviderConfig = () => { (config: AWSWorkerConfig | undefined) => { if (!config) { dispatch(reinitializeAWSConfig()); + setEnabled(false); return; } + setEnabled(true); + const { bucket, credentials } = config; if (bucket && bucket !== '') { dispatch(changeAWSBucketName(bucket)); @@ -88,7 +97,7 @@ export const CloudProviderConfig = () => { dispatch(changeAWSCredsPath(credentials)); } }, - [dispatch] + [dispatch, setEnabled], ); useEffect(() => { @@ -126,7 +135,8 @@ export const CloudProviderConfig = () => { 0)} + enabled={enabled} + setEnabled={setEnabled} />