Fix/issue 46081 fetch with error throwing network error (#47597)
Some checks are pending
Weblate Sync / Trigger Weblate to pull the latest changes (push) Waiting to run

closes #46081


Signed-off-by: Jimmy Chakkalakal <jimmy.chakkalakal@ibm.com>
This commit is contained in:
jimmychakkalakal 2026-04-01 11:53:25 +01:00 committed by GitHub
parent be17c5e747
commit f1055ab5ab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 98 additions and 29 deletions

View file

@ -1,6 +1,7 @@
import { expect, test } from "@playwright/test";
import { assertLastAlert, login } from "../support/actions.ts";
import { createTestBed } from "../support/testbed.ts";
import { retryOperation, waitForRealmReady } from "../support/test-utils.ts";
import userProfile from "./user-profile.json" with { type: "json" };
import { adminClient } from "../support/admin-client.ts";
import userProfileRealm from "../realms/user-profile-realm.json" with { type: "json" };
@ -23,68 +24,80 @@ test.describe("Personal info", () => {
test.describe("Personal info (user profile enabled)", () => {
test("renders user profile fields", async ({ page }) => {
await using testBed = await createTestBed(userProfileRealm);
await waitForRealmReady();
await adminClient.users.updateProfile({
...userProfile,
realm: testBed.realm,
});
await retryOperation(() =>
adminClient.users.updateProfile({
...userProfile,
realm: testBed.realm,
}),
);
await login(page, testBed.realm);
await expect(page.locator("#select")).toBeVisible();
await expect(page.getByTestId("help-label-select")).toBeVisible();
await expect(page.getByText("Alternative email")).toHaveCount(1);
await expect(page.getByPlaceholder("Deutsch")).toHaveCount(1);
await expect(page.getByText("Alternative email")).toBeVisible();
await expect(page.getByPlaceholder("Deutsch")).toBeVisible();
await page.getByTestId("help-label-email2").click();
await expect(page.getByText("Español")).toHaveCount(1);
await expect(page.getByText("Español")).toBeVisible();
});
test("renders long select options as typeahead", async ({ page }) => {
await using testBed = await createTestBed(userProfileRealm);
await waitForRealmReady();
await adminClient.users.updateProfile({
...userProfile,
realm: testBed.realm,
});
await retryOperation(() =>
adminClient.users.updateProfile({
...userProfile,
realm: testBed.realm,
}),
);
await login(page, testBed.realm);
await page.locator("#alternatelang").click();
await page.waitForSelector("text=Italiano");
await expect(page.getByText("Italiano")).toBeVisible();
await page.locator("#alternatelang").click();
await page.locator("*:focus").press("Control+A");
await page.locator("*:focus").pressSequentially("S");
await expect(page.getByText("Italiano")).toHaveCount(0);
await expect(page.getByText("Italiano")).toBeHidden();
await expect(page.getByText("Slovak")).toBeVisible();
await expect(page.getByText('Create "S"')).toBeHidden();
});
test("renders long list of locales as typeahead", async ({ page }) => {
await using testBed = await createTestBed(userProfileRealm);
await waitForRealmReady();
await adminClient.users.updateProfile({
...userProfile,
realm: testBed.realm,
});
await retryOperation(() =>
adminClient.users.updateProfile({
...userProfile,
realm: testBed.realm,
}),
);
await login(page, testBed.realm);
await page.locator("#attributes\\.locale").click();
await page.waitForSelector("text=Italiano");
await expect(page.getByText("Italiano")).toBeVisible();
await page.locator("#attributes\\.locale").click();
await page.locator("*:focus").press("Control+A");
await page.locator("*:focus").pressSequentially("S");
await expect(page.getByText("Italiano")).toHaveCount(0);
await expect(page.getByText("Italiano")).toBeHidden();
await expect(page.getByText("Slovak")).toBeVisible();
await expect(page.getByText('Create "S"')).toBeHidden();
});
test("saves user profile", async ({ page }) => {
await using testBed = await createTestBed(userProfileRealm);
await waitForRealmReady();
await adminClient.users.updateProfile({
...userProfile,
realm: testBed.realm,
});
await retryOperation(() =>
adminClient.users.updateProfile({
...userProfile,
realm: testBed.realm,
}),
);
await login(page, testBed.realm);
await page.locator("#select").click();
@ -106,7 +119,6 @@ test.describe("Personal info (user profile enabled)", () => {
await assertLastAlert(page, "Your account has been updated.");
await page.reload();
await page.locator("delete-account").isVisible();
await expect(page.getByTestId("email2")).toHaveValue("valid@email.com");
});
});
@ -117,18 +129,25 @@ test.describe("Realm localization", () => {
internationalizationEnabled: true,
supportedLocales: ["en", "nl", "de"],
});
await waitForRealmReady();
await login(page, testBed.realm);
await page.locator("#attributes\\.locale").waitFor({ state: "visible" });
await page.locator("#attributes\\.locale").click();
page.getByRole("option").filter({ hasText: "Deutsch" });
await page
.getByRole("option", { name: "English" })
.waitFor({ state: "visible" });
await page.getByRole("option", { name: "English" }).click();
await page.getByTestId("save").click();
await assertLastAlert(page, "Your account has been updated.");
await page.reload();
expect(
page.locator("#attributes\\.locale").filter({ hasText: /^English$/ }),
).toBeDefined();
await page.locator("#attributes\\.locale").waitFor({ state: "visible" });
await expect(page.locator("#attributes\\.locale")).toContainText("English");
});
});

View file

@ -3,15 +3,22 @@ import { expect, test } from "@playwright/test";
import resourcesRealm from "./realms/resources-realm.json" with { type: "json" };
import { login } from "./support/actions.ts";
import { createTestBed } from "./support/testbed.ts";
import { waitForRealmReady } from "./support/test-utils.ts";
test.describe("Resources", () => {
test("shows the resources owned by the user", async ({ page }) => {
await using testBed = await createTestBed(
resourcesRealm as RealmRepresentation,
);
await waitForRealmReady();
await login(page, testBed.realm);
const responsePromise = page.waitForResponse(
(resp) => resp.url().includes("/realms/") && resp.status() === 200,
);
await page.getByTestId("resources").click();
await responsePromise;
await expect(page.getByRole("gridcell", { name: "one" })).toBeVisible();
});
@ -20,11 +27,14 @@ test.describe("Resources", () => {
await using testBed = await createTestBed(
resourcesRealm as RealmRepresentation,
);
await waitForRealmReady();
await login(page, testBed.realm, "alice", "alice");
await page.getByTestId("resources").click();
await page.getByTestId("sharedWithMe").click();
const table = page.locator("table");
await expect(table).toBeVisible();
const tableData = await page.locator("table > tr").count();
expect(tableData).toBe(0);
});
@ -33,6 +43,7 @@ test.describe("Resources", () => {
await using testBed = await createTestBed(
resourcesRealm as RealmRepresentation,
);
await waitForRealmReady();
await using context1 = await browser.newContext();
await using context2 = await browser.newContext();
@ -76,6 +87,8 @@ test.describe("Resources", () => {
await page2.getByTestId("resources").click();
await page2.getByTestId("sharedWithMe").click();
const table = page2.locator("table");
await expect(table).toBeVisible();
const rowData = page2.getByTestId("row[0].name");
await expect(rowData).toHaveText("one");
});

View file

@ -0,0 +1,37 @@
export async function retryOperation<T>(
operation: () => Promise<T>,
maxRetries = 15,
initialDelay = 300,
): Promise<T> {
let lastError: Error | undefined;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error as Error;
// Only retry on server errors or network errors, not on validation errors
const isRetryableError =
error instanceof Error &&
(error.message.includes("unknown_error") ||
error.message.includes("500") ||
error.message.includes("ECONNREFUSED"));
if (isRetryableError) {
const delay = initialDelay * Math.pow(1.5, attempt);
await new Promise((resolve) => setTimeout(resolve, delay));
continue;
}
// For other errors (validation, 4xx, etc.), throw immediately
throw error;
}
}
throw lastError;
}
export async function waitForRealmReady(delayMs = 500): Promise<void> {
await new Promise((resolve) => setTimeout(resolve, delayMs));
}