Files
wehub-resource-sync bf2343b7e4
Integration Tests - MySQL + Elasticsearch / Detect Changes (push) Waiting to run
Integration Tests - MySQL + Elasticsearch / integration-tests-mysql-elasticsearch (push) Blocked by required conditions
Integration Tests - PostgreSQL + Elasticsearch + Redis / Detect Changes (push) Waiting to run
Integration Tests - PostgreSQL + Elasticsearch + Redis / integration-tests-postgres-elasticsearch-redis (push) Blocked by required conditions
Integration Tests - PostgreSQL + OpenSearch / Detect Changes (push) Waiting to run
Integration Tests - PostgreSQL + OpenSearch / integration-tests-postgres-opensearch (push) Blocked by required conditions
Java Checkstyle / java-checkstyle (push) Waiting to run
Maven Collate Tests / maven-collate-ci (push) Waiting to run
OpenMetadata Service Unit Tests / Detect Changes (push) Waiting to run
OpenMetadata Service Unit Tests / openmetadata-service-unit-tests (push) Blocked by required conditions
OpenMetadata Service Unit Tests / k8s_operator-unit-tests (push) Blocked by required conditions
OpenMetadata Service Unit Tests / openmetadata-service-unit-tests-status (push) Blocked by required conditions
Publish Package to Maven Central Repository / publish-maven-packages (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:35:45 +08:00

5.8 KiB

UI test conventions

Read this before writing or porting any *UIIT.java. It exists so the suite stays consistent as we migrate 258 specs.

Layering — strict, top-only depends down

playwright.scenarios.<domain>.*UIIT.java        — tests
        ↓
playwright.ui.pages.*Page.java                  — Page Objects (locators + actions)
        ↓
playwright.ui.{SessionBrowser,UiSession,UiSessionExtension,TraceRecorder}
it.auth.{AuthBackend,AuthSession,BasicJwtBackend,OidcBackend,…}
        ↓
it.server.*, it.search.*                        — server lifecycle + SDK helpers

Rule: prefer keeping Locator / Page / BrowserContext use inside Page Objects. Page Objects may expose Locator-returning accessors when a test legitimately needs to make a Playwright-level assertion on a specific element, and PageObject.rawPage() is a documented escape hatch for URL assertions and SSO redirect flows. If a test reaches for Playwright primitives for routine interactions (clicks, typing, navigation), promote the interaction into a Page Object method.

Test skeleton

@ExtendWith({UiSessionExtension.class, TestNamespaceExtension.class})
class FooUIIT {

  @BeforeAll
  static void setup() {
    SdkClients.useFluentApis(UiTestServer.get().sdk());
    Apps.setDefaultClient(UiTestServer.get().sdk());
  }

  @Test
  void scenario(final UiSession ui, final TestNamespace ns) {
    Table t = TableTestFactory.createSimple(ns);                     // SDK setup
    FooPage page = FooPage.open(ui, t.getFullyQualifiedName());      // page object navigation
    page.doSomething();                                              // page object action
    assertThat(page.someResult()).isVisible();                       // assertion
  }
}

Setup via SDK. Cleanup via TestNamespace. Never click through the UI to seed state.

Page Objects

  • One class per page, ≤ 200 lines. Split if bigger.
  • Static open(...) factory navigates and returns a loaded instance.
  • Actions return this (or another PageObject) for chaining.
  • Locators: getByTestId > getByRole/getByLabel > getByPlaceholder > text > CSS.
  • Define every selector as private static final — no inline literals.
  • waitForLoaded() overridden per page — the readiness signal must be page-specific (a known testid visible, an API response done) not a generic networkidle if a better signal exists.

Auth

The whole suite is parameterized by an AuthBackend. Pick one with -Djpw.auth=<name> (or JPW_AUTH=<name>); the same UI tests run unchanged regardless of which is active.

jpw.auth OM auth provider Token acquired by
basic (default) OM built-in JWT JwtAuthProvider (admin signing key)
sso-google-public Google + public client (response_type=id_token) mock IdP /google/token (password grant)
sso-google-confidential Google + confidential client (response_type=code) same
sso-okta-public Okta + public client mock IdP /okta/token
sso-okta-confidential Okta + confidential client same
sso-custom-oidc-public Custom OIDC + public mock IdP /custom-oidc/token
sso-custom-oidc-confidential Custom OIDC + confidential same

Per-test override (only when the test explicitly drives the sign-in surface and doesn't want a token preloaded):

@Test
@NoPreloadAuth
void clickingSignInWithGoogleCompletesLogin(UiSession ui) { ... }

Tests that only make sense under one backend gate themselves with AuthAssumptions.onlyWhenBackendIs("sso-google-confidential"). They skip cleanly when the suite is running under any other backend.

A daemon TokenRefresher keeps AuthSession.current() valid across long runs; tests read the current token at @BeforeEach, so refresh is transparent.

Parallelism

  • Per-method parallel by default; classes serial. Configured in pom failsafe.
  • Tests that mutate global state must be tagged:
    • @ResourceLock("GLOBAL_SETTINGS") — settings, themes, login config
    • @ResourceLock("SEARCH_INDEX_APP") — re-triggers the global reindex app
    • @ResourceLock("APPS") — install/uninstall apps
    • @ResourceLock("ALERTS") — global alert config
    • @Execution(SAME_THREAD) — inherently sequential UI flows (Tour, SSO renewal)
  • Default: assume parallel-safe. TestNamespace keeps entity names unique.

Java code rules (recap from project CLAUDE.md)

  • Methods ≤ 15 lines, ≤ 3 nesting, ≤ 5 params, ≤ 10 cyclomatic.
  • final on every parameter and local that doesn't change.
  • No comments stating what — only why. Name the code so it reads.
  • No magic strings in equals/contains/switch — define a constant or an enum.
  • No deep else if chains — refactor to switch, Map dispatch, or named predicate.
  • No empty catches, no printStackTrace, no catch(Exception) for control flow.
  • mvn spotless:apply before every commit.

Headed debugging

Knobs (all available as env var or -D<name>=... system property):

Knob Effect
PW_HEADED=true Visible Chromium
PW_SLOWMO=<ms> Inter-action delay; defaults to 250ms in headed, 0 in headless
PW_VIDEO=true Records every test, saves to target/playwright-videos/<class>-<test>-<ts>.webm

Trace zips for failed runs are saved to target/playwright-traces/. Replay any trace:

npx playwright show-trace target/playwright-traces/trace-<class>-<test>-<ts>.zip

Typical local debug recipe — slow it down enough to follow, capture video for review:

PW_HEADED=true PW_SLOWMO=500 PW_VIDEO=true mvn verify -P ui-it \
  -pl :openmetadata-integration-tests -Dit.test='SimpleReindexTriggerUIIT'

When in doubt

  • Read REINDEX_TEST_PLAN.md at the module root for the reindex scenario coverage map.
  • Read SimpleReindexTriggerUIIT as the canonical reference test.