Skip to content

Commit 1de75ee

Browse files
feat(e2e): enable oxlint pedantic category (#5003)
* feat(e2e): enable oxlint pedantic and burn down violations Turn on pedantic-as-error with prefer-readonly-parameter-types disabled for test helpers, then fix ~635 violations via stricter booleans, nullish coalescing, module splits for oversized files, and deprecated selector migrations. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(e2e): replace oxlint file exceptions with path patterns Use directory globs instead of named files and document the rationale for each override block. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(e2e): apply Playwright assertion fixes in oxlint pedantic PR Use plain await for deployment restart, expect().toBeVisible() for the About card link, and table-scoped verifyText for catalog Name checks. Register restartDeployment as an assert helper for expect-expect. Co-authored-by: Cursor <cursoragent@cursor.com> * chore(e2e): reformat after pedantic rebase onto Oxfmt defaults Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(e2e): group split modules into folders for clearer naming Move kube-client, api-helper, common, rhdh-deployment, and semantic selector splits into directories with short filenames, matching the ui-helper pattern. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(e2e): use folder index entry points for all split utils Remove redundant top-level common.ts and ui-helper.ts facades so split modules match api-helper and kube-client (folder + index only). Add ui-helper/index.ts and move msgraph-helper split into msgraph-helper/. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(e2e): correct relative imports after utils folder split Folder moves left one-level-too-shallow paths to errors, api-endpoints, support, and locale modules, which broke type-aware oxlint in CI. Use global fetch in keycloak helper now that Node 24 provides it natively. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(e2e): restore legacy card/table scoping for home page tests Semantic getAccordion/getCard/getTableRow locators were too narrow or ambiguous for MUI home page and scaffolder review tables. Scope quick access items to the accordion root, cards via MuiCard XPath, and rows via :text-is() matching until semantic selectors cover these layouts. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 7c2ecd5 commit 1de75ee

104 files changed

Lines changed: 7614 additions & 6353 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

e2e-tests/oxlint.config.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export default defineConfig({
55
categories: {
66
correctness: "error",
77
suspicious: "error",
8+
pedantic: "error",
89
},
910
options: {
1011
typeAware: true,
@@ -17,6 +18,7 @@ export default defineConfig({
1718
"test-results/**",
1819
"coverage/**",
1920
".local-test/**",
21+
"scripts/**",
2022
],
2123
rules: {
2224
"typescript/no-floating-promises": "error",
@@ -26,6 +28,7 @@ export default defineConfig({
2628
"typescript/no-unsafe-call": "error",
2729
"typescript/no-unsafe-return": "error",
2830
"typescript/strict-void-return": "error",
31+
"typescript/prefer-readonly-parameter-types": "off",
2932
"check-file/filename-naming-convention": [
3033
"error",
3134
{
@@ -61,12 +64,57 @@ export default defineConfig({
6164
},
6265
overrides: [
6366
{
67+
// Auth-provider specs deploy RHDH in beforeAll and use async Playwright hooks.
68+
// strict-void-return and no-misused-promises produce false positives on those
69+
// describe/beforeAll callbacks without improving test safety.
6470
files: ["playwright/e2e/auth-providers/**/*.spec.ts"],
6571
rules: {
6672
"typescript/strict-void-return": "off",
73+
"typescript/no-misused-promises": "off",
6774
},
6875
},
6976
{
77+
// Spec files orchestrate multi-step E2E flows; length limits target production
78+
// code readability, not test scenarios that must stay in one file for clarity.
79+
files: ["**/*.spec.ts", "**/*.test.ts"],
80+
rules: {
81+
"eslint/max-lines": "off",
82+
"eslint/max-lines-per-function": "off",
83+
},
84+
},
85+
{
86+
// Shared infrastructure (utils, support, data, e2e helpers) is split into
87+
// modules but still contains cohesive orchestration (kube waits, deployment
88+
// setup, log parsing). Complexity limits would force artificial fragmentation.
89+
files: [
90+
"playwright/utils/**/*.ts",
91+
"playwright/support/**/*.ts",
92+
"playwright/data/**/*.ts",
93+
"playwright/e2e/**/*.ts",
94+
],
95+
rules: {
96+
"eslint/max-lines": "off",
97+
"eslint/max-lines-per-function": "off",
98+
"eslint/max-depth": "off",
99+
},
100+
},
101+
{
102+
// Facade modules aggregate many submodules by design (e.g. KubeClient re-exports,
103+
// rhdh-deployment orchestration, locale translation maps). A flat import count
104+
// does not reflect coupling when each import is a focused submodule.
105+
files: ["playwright/utils/**/*.ts", "playwright/e2e/localization/**/*.ts"],
106+
rules: {
107+
"import/max-dependencies": "off",
108+
},
109+
},
110+
{
111+
// valid-title / valid-describe-callback: existing suite uses legacy naming
112+
// patterns that do not match the plugin's strict conventions.
113+
// no-wait-for-selector: replaced with expect() and locator.waitFor() per
114+
// hardening guidelines; rule would flag intentional migration patterns.
115+
// expect-expect + assertFunctionNames: POM verify* helpers and loginAsGuest
116+
// perform assertions on behalf of the spec; register them so specs are not
117+
// forced to duplicate expect() calls after every helper invocation.
70118
files: ["**/*.spec.ts", "**/*.test.ts", "playwright/**/*.ts"],
71119
rules: {
72120
// Playwright requires object destructuring for hook/test callbacks that take
@@ -107,6 +155,7 @@ export default defineConfig({
107155
"verifyTextInSelector",
108156
"verifyPartialTextInSelector",
109157
"loginAsGuest",
158+
"restartDeployment",
110159
"waitForTitle",
111160
],
112161
},

e2e-tests/playwright.config.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import type { ReporterDescription } from "@playwright/test";
33

44
import { PW_PROJECT } from "./playwright/projects";
55

6-
process.env.JOB_NAME = process.env.JOB_NAME || "";
7-
process.env.IS_OPENSHIFT = process.env.IS_OPENSHIFT || "";
6+
process.env.JOB_NAME = process.env.JOB_NAME ?? "";
7+
process.env.IS_OPENSHIFT = process.env.IS_OPENSHIFT ?? "";
88

99
// Set LOCALE based on which project is being run
1010
const args = process.argv;
@@ -19,26 +19,27 @@ if (args.some((arg) => arg.includes(PW_PROJECT.SHOWCASE_LOCALIZATION_DE))) {
1919
process.env.LOCALE = "it";
2020
} else if (args.some((arg) => arg.includes(PW_PROJECT.SHOWCASE_LOCALIZATION_JA))) {
2121
process.env.LOCALE = "ja";
22-
} else if (!process.env.LOCALE) {
22+
} else if (process.env.LOCALE === undefined || process.env.LOCALE === "") {
2323
process.env.LOCALE = "en";
2424
}
2525

2626
const k8sSpecificConfig = {
2727
use: {
2828
actionTimeout: 15 * 1000,
2929
},
30+
// Global expect timeout
3031
expect: {
31-
timeout: 15 * 1000, // Global expect timeout
32+
timeout: 15 * 1000,
3233
},
3334
};
3435

3536
export default defineConfig({
3637
timeout: 90 * 1000,
3738
testDir: "./playwright",
3839
/* Fail the build on CI if you accidentally left test.only in the source code. */
39-
forbidOnly: !!process.env.CI,
40+
forbidOnly: process.env.CI !== undefined && process.env.CI !== "",
4041
/* Retry on CI only */
41-
retries: process.env.CI ? 2 : 0,
42+
retries: process.env.CI !== undefined && process.env.CI !== "" ? 2 : 0,
4243
/* Opt out of parallel tests on CI. */
4344
workers: 3,
4445
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
@@ -47,14 +48,14 @@ export default defineConfig({
4748
reporter: [
4849
["html"],
4950
["list"],
50-
["junit", { outputFile: process.env.JUNIT_RESULTS || "junit-results.xml" }],
51+
["junit", { outputFile: process.env.JUNIT_RESULTS ?? "junit-results.xml" }],
5152
...(process.env.COLLECT_COVERAGE === "true"
5253
? ([["./playwright/support/coverage/reporter.ts"]] satisfies ReporterDescription[])
5354
: []),
5455
],
5556
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
5657
use: {
57-
locale: process.env.LOCALE || "en",
58+
locale: process.env.LOCALE ?? "en",
5859
baseURL: process.env.BASE_URL,
5960
ignoreHTTPSErrors: true,
6061
trace: "on",
@@ -72,8 +73,9 @@ export default defineConfig({
7273
actionTimeout: 10 * 1000,
7374
navigationTimeout: 50 * 1000,
7475
},
76+
// Global expect timeout
7577
expect: {
76-
timeout: 10 * 1000, // Global expect timeout
78+
timeout: 10 * 1000,
7779
},
7880

7981
/* Configure projects for major browsers */
@@ -110,7 +112,8 @@ export default defineConfig({
110112
name: PW_PROJECT.SHOWCASE_AUTH_PROVIDERS,
111113
testMatch: ["**/playwright/e2e/auth-providers/*.spec.ts"],
112114
testIgnore: [
113-
"**/playwright/e2e/auth-providers/github-happy-path.spec.ts", // temporarily disable
115+
// temporarily disable github-happy-path
116+
"**/playwright/e2e/auth-providers/github-happy-path.spec.ts",
114117
"**/playwright/e2e/external-database/verify-tls-config-with-external-rds.spec.ts",
115118
"**/playwright/e2e/external-database/verify-tls-config-with-external-azure-db.spec.ts",
116119
],
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import { Policy } from "../support/api/rbac-api-structures";
2+
3+
export const EXPECTED_POLICIES: Policy[] = [
4+
{
5+
entityReference: "role:default/rbac_admin",
6+
permission: "policy-entity",
7+
policy: "read",
8+
effect: "allow",
9+
},
10+
{
11+
entityReference: "role:default/rbac_admin",
12+
permission: "policy.entity.create",
13+
policy: "create",
14+
effect: "allow",
15+
},
16+
{
17+
entityReference: "role:default/rbac_admin",
18+
permission: "policy-entity",
19+
policy: "delete",
20+
effect: "allow",
21+
},
22+
{
23+
entityReference: "role:default/rbac_admin",
24+
permission: "policy-entity",
25+
policy: "update",
26+
effect: "allow",
27+
},
28+
{
29+
entityReference: "role:default/rbac_admin",
30+
permission: "catalog-entity",
31+
policy: "read",
32+
effect: "allow",
33+
},
34+
{
35+
entityReference: "role:default/guests",
36+
permission: "catalog.entity.create",
37+
policy: "create",
38+
effect: "allow",
39+
},
40+
{
41+
entityReference: "role:default/team_a",
42+
permission: "catalog-entity",
43+
policy: "read",
44+
effect: "allow",
45+
},
46+
{
47+
entityReference: "role:xyz/team_a",
48+
permission: "catalog-entity",
49+
policy: "read",
50+
effect: "allow",
51+
},
52+
{
53+
entityReference: "role:xyz/team_a",
54+
permission: "catalog.entity.create",
55+
policy: "create",
56+
effect: "allow",
57+
},
58+
{
59+
entityReference: "role:xyz/team_a",
60+
permission: "catalog.location.create",
61+
policy: "create",
62+
effect: "allow",
63+
},
64+
{
65+
entityReference: "role:xyz/team_a",
66+
permission: "catalog.location.read",
67+
policy: "read",
68+
effect: "allow",
69+
},
70+
{
71+
entityReference: "role:default/qe_rbac_admin",
72+
permission: "kubernetes.proxy",
73+
policy: "use",
74+
effect: "allow",
75+
},
76+
{
77+
entityReference: "role:default/qe_rbac_admin",
78+
permission: "kubernetes.resources.read",
79+
policy: "read",
80+
effect: "allow",
81+
},
82+
{
83+
entityReference: "role:default/qe_rbac_admin",
84+
permission: "kubernetes.clusters.read",
85+
policy: "read",
86+
effect: "allow",
87+
},
88+
{
89+
entityReference: "role:default/qe_rbac_admin",
90+
permission: "catalog.entity.create",
91+
policy: "create",
92+
effect: "allow",
93+
},
94+
{
95+
entityReference: "role:default/qe_rbac_admin",
96+
permission: "catalog.location.create",
97+
policy: "create",
98+
effect: "allow",
99+
},
100+
{
101+
entityReference: "role:default/qe_rbac_admin",
102+
permission: "catalog.location.read",
103+
policy: "read",
104+
effect: "allow",
105+
},
106+
{
107+
entityReference: "role:default/kubernetes_reader",
108+
permission: "kubernetes.resources.read",
109+
policy: "read",
110+
effect: "allow",
111+
},
112+
{
113+
entityReference: "role:default/kubernetes_reader",
114+
permission: "kubernetes.clusters.read",
115+
policy: "read",
116+
effect: "allow",
117+
},
118+
{
119+
entityReference: "role:default/catalog_reader",
120+
permission: "catalog.entity.read",
121+
policy: "read",
122+
effect: "allow",
123+
},
124+
{
125+
entityReference: "role:default/all_resource_reader",
126+
permission: "catalog-entity",
127+
policy: "read",
128+
effect: "allow",
129+
},
130+
{
131+
entityReference: "role:default/all_resource_reader",
132+
permission: "catalog-entity",
133+
policy: "create",
134+
effect: "allow",
135+
},
136+
{
137+
entityReference: "role:default/all_resource_denier",
138+
permission: "catalog-entity",
139+
policy: "read",
140+
effect: "deny",
141+
},
142+
{
143+
entityReference: "role:default/all_resource_denier",
144+
permission: "catalog-entity",
145+
policy: "create",
146+
effect: "allow",
147+
},
148+
];
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { Role } from "../support/api/rbac-api-structures";
2+
3+
export const EXPECTED_ROLES: Role[] = [
4+
{
5+
memberReferences: ["user:default/rhdh-qe"],
6+
name: "role:default/rbac_admin",
7+
},
8+
{
9+
memberReferences: ["user:default/guest"],
10+
name: "role:default/guests",
11+
},
12+
{
13+
memberReferences: ["user:default/user_team_a", "user:default/rhdh-qe"],
14+
name: "role:default/team_a",
15+
},
16+
{
17+
memberReferences: ["user:xyz/user"],
18+
name: "role:xyz/team_a",
19+
},
20+
{
21+
memberReferences: ["group:default/rhdh-qe-2-team"],
22+
name: "role:default/test2-role",
23+
},
24+
{
25+
memberReferences: ["user:default/rhdh-qe"],
26+
name: "role:default/qe_rbac_admin",
27+
},
28+
{
29+
memberReferences: ["group:default/rhdh-qe-parent-team", "group:default/rhdh-qe-child-team"],
30+
name: "role:default/transitive-owner",
31+
},
32+
{
33+
memberReferences: ["user:default/rhdh-qe-5"],
34+
name: "role:default/kubernetes_reader",
35+
},
36+
{
37+
memberReferences: ["user:default/rhdh-qe-5", "user:default/rhdh-qe-6"],
38+
name: "role:default/catalog_reader",
39+
},
40+
{
41+
memberReferences: ["user:default/rhdh-qe-7", "user:default/rhdh-qe-9"],
42+
name: "role:default/all_resource_reader",
43+
},
44+
{
45+
memberReferences: ["user:default/rhdh-qe-8"],
46+
name: "role:default/all_resource_denier",
47+
},
48+
{
49+
memberReferences: ["user:default/rhdh-qe-7", "user:default/rhdh-qe-8"],
50+
name: "role:default/owned_resource_reader",
51+
},
52+
{
53+
memberReferences: ["user:default/rhdh-qe-9"],
54+
name: "role:default/conditional_denier",
55+
},
56+
];

0 commit comments

Comments
 (0)