Skip to content

Commit 9a8dd0e

Browse files
Merge pull request #518 from DavidRajnoha/cypress-commands-refactor
OBSINTA-796: Refactor Cypress Commands Structure
2 parents 0a946e3 + fd0bc7e commit 9a8dd0e

8 files changed

Lines changed: 738 additions & 738 deletions

File tree

web/cypress/support/commands.ts

Lines changed: 0 additions & 711 deletions
This file was deleted.
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import { guidedTour } from '../../views/tour';
2+
import { nav } from '../../views/nav';
3+
4+
5+
6+
export {};
7+
declare global {
8+
namespace Cypress {
9+
interface Chainable {
10+
switchPerspective(perspective: string);
11+
uiLogin(provider: string, username: string, password: string, oauthurl?: string);
12+
uiLogout();
13+
cliLogin(username?, password?, hostapi?);
14+
cliLogout();
15+
login(provider?: string, username?: string, password?: string, oauthurl?: string): Chainable<Element>;
16+
adminCLI(command: string, options?);
17+
executeAndDelete(command: string);
18+
}
19+
}
20+
}
21+
22+
23+
Cypress.Commands.add(
24+
'login',
25+
(
26+
provider: string = Cypress.env('LOGIN_IDP'),
27+
username: string = Cypress.env('LOGIN_USERNAME'),
28+
password: string = Cypress.env('LOGIN_PASSWORD'),
29+
oauthurl: string,
30+
) => {
31+
cy.session(
32+
[provider, username],
33+
() => {
34+
cy.visit(Cypress.config('baseUrl'));
35+
cy.log('Session - after visiting');
36+
cy.window().then(
37+
(
38+
win: any, // eslint-disable-line @typescript-eslint/no-explicit-any
39+
) => {
40+
// Check if auth is disabled (for a local development environment)
41+
if (win.SERVER_FLAGS?.authDisabled) {
42+
cy.task('log', ' skipping login, console is running with auth disabled');
43+
return;
44+
}
45+
cy.exec(
46+
`oc get node --selector=hypershift.openshift.io/managed --kubeconfig ${Cypress.env('KUBECONFIG_PATH')}`,
47+
).then((result) => {
48+
cy.log(result.stdout);
49+
cy.task('log', result.stdout);
50+
if (result.stdout.includes('Ready')) {
51+
cy.log(`Attempting login via cy.origin to: ${oauthurl}`);
52+
cy.task('log', `Attempting login via cy.origin to: ${oauthurl}`);
53+
cy.origin(
54+
oauthurl,
55+
{ args: { username, password } },
56+
({ username, password }) => {
57+
cy.get('#inputUsername').type(username);
58+
cy.get('#inputPassword').type(password);
59+
cy.get('button[type=submit]').click();
60+
},
61+
);
62+
} else {
63+
cy.task('log', ` Logging in as ${username} using fallback on ${oauthurl}`);
64+
cy.origin(
65+
oauthurl,
66+
{ args: { provider, username, password } },
67+
({ provider, username, password }) => {
68+
cy.get('[data-test-id="login"]').should('be.visible');
69+
cy.get('body').then(($body) => {
70+
if ($body.text().includes(provider)) {
71+
cy.contains(provider).should('be.visible').click();
72+
}
73+
});
74+
cy.get('#inputUsername').type(username);
75+
cy.get('#inputPassword').type(password);
76+
cy.get('button[type=submit]').click();
77+
}
78+
);
79+
}
80+
});
81+
},
82+
);
83+
},
84+
{
85+
cacheAcrossSpecs: true,
86+
validate() {
87+
cy.visit('/');
88+
cy.byTestID("username", {timeout: 120000}).should('be.visible');
89+
guidedTour.close();
90+
},
91+
},
92+
);
93+
},
94+
);
95+
96+
Cypress.Commands.add('switchPerspective', (perspective: string) => {
97+
/* If side bar is collapsed then expand it
98+
before switching perspecting */
99+
cy.get('body').then((body) => {
100+
if (body.find('.pf-m-collapsed').length > 0) {
101+
cy.get('#nav-toggle').click();
102+
}
103+
});
104+
nav.sidenav.switcher.changePerspectiveTo(perspective);
105+
nav.sidenav.switcher.shouldHaveText(perspective);
106+
});
107+
108+
// To avoid influence from upstream login change
109+
Cypress.Commands.add('uiLogin', (provider: string, username: string, password: string) => {
110+
cy.log('Commands uiLogin');
111+
cy.clearCookie('openshift-session-token');
112+
cy.visit('/');
113+
cy.window().then(
114+
(
115+
win: any, // eslint-disable-line @typescript-eslint/no-explicit-any
116+
) => {
117+
if (win.SERVER_FLAGS?.authDisabled) {
118+
cy.task('log', 'Skipping login, console is running with auth disabled');
119+
return;
120+
}
121+
cy.get('[data-test-id="login"]').should('be.visible');
122+
cy.get('body').then(($body) => {
123+
if ($body.text().includes(provider)) {
124+
cy.contains(provider).should('be.visible').click();
125+
} else if ($body.find('li.idp').length > 0) {
126+
//Using the last idp if doesn't provider idp name
127+
cy.get('li.idp').last().click();
128+
}
129+
});
130+
cy.get('#inputUsername').type(username);
131+
cy.get('#inputPassword').type(password);
132+
cy.get('button[type=submit]').click();
133+
cy.byTestID('username', { timeout: 120000 }).should('be.visible');
134+
},
135+
);
136+
cy.switchPerspective('Administrator');
137+
});
138+
139+
Cypress.Commands.add('uiLogout', () => {
140+
cy.window().then(
141+
(
142+
win: any, // eslint-disable-line @typescript-eslint/no-explicit-any
143+
) => {
144+
if (win.SERVER_FLAGS?.authDisabled) {
145+
cy.log('Skipping logout, console is running with auth disabled');
146+
return;
147+
}
148+
cy.log('Log out UI');
149+
cy.byTestID('username').click();
150+
cy.byTestID('log-out').should('be.visible');
151+
cy.byTestID('log-out').click({ force: true });
152+
},
153+
);
154+
});
155+
156+
Cypress.Commands.add('cliLogin', (username?, password?, hostapi?) => {
157+
const loginUsername = username || Cypress.env('LOGIN_USERNAME');
158+
const loginPassword = password || Cypress.env('LOGIN_PASSWORD');
159+
const hostapiurl = hostapi || Cypress.env('HOST_API');
160+
cy.exec(
161+
`oc login -u ${loginUsername} -p ${loginPassword} ${hostapiurl} --insecure-skip-tls-verify=true`,
162+
{ failOnNonZeroExit: false },
163+
).then((result) => {
164+
cy.log(result.stderr);
165+
cy.log(result.stdout);
166+
});
167+
});
168+
169+
Cypress.Commands.add('cliLogout', () => {
170+
cy.exec(`oc logout`, { failOnNonZeroExit: false }).then((result) => {
171+
cy.log(result.stderr);
172+
cy.log(result.stdout);
173+
});
174+
});
175+
176+
Cypress.Commands.add('adminCLI', (command: string) => {
177+
const kubeconfig = Cypress.env('KUBECONFIG_PATH');
178+
cy.log(`Run admin command: ${command}`);
179+
cy.exec(`${command} --kubeconfig ${kubeconfig}`);
180+
});
181+
182+
Cypress.Commands.add('executeAndDelete', (command: string) => {
183+
cy.exec(command, { failOnNonZeroExit: false })
184+
.then(result => {
185+
if (result.code !== 0) {
186+
cy.task('logError', `Command "${command}" failed: ${result.stderr || result.stdout}`);
187+
} else {
188+
cy.task('log', `Command "${command}" executed successfully`);
189+
}
190+
});
191+
});
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
export {};
2+
3+
declare global {
4+
namespace Cypress {
5+
interface Chainable {
6+
createKubePodCrashLoopingAlert(): Chainable<string>;
7+
cleanupIncidentPrometheusRules(): Chainable<Element>;
8+
}
9+
}
10+
}
11+
12+
13+
// Apply incident fixture manifests to the cluster
14+
Cypress.Commands.add('createKubePodCrashLoopingAlert', () => {
15+
const kubeconfigPath = Cypress.env('KUBECONFIG_PATH');
16+
17+
// Generate a random alert name for this test run
18+
const randomAlertName = `CustomPodCrashLooping_${Math.random().toString(36).substring(2, 15)}`;
19+
20+
// Store the alert name globally so tests can access it
21+
Cypress.env('CURRENT_ALERT_NAME', randomAlertName);
22+
23+
cy.log(`Generated random alert name: ${randomAlertName}`);
24+
25+
// Read the template and replace the placeholder
26+
cy.readFile('./cypress/fixtures/incidents/prometheus_rule_pod_crash_loop.yaml').then((template) => {
27+
const yamlContent = template.replace(/\{\{ALERT_NAME\}\}/g, randomAlertName);
28+
29+
// Write the modified YAML to a temporary file
30+
cy.writeFile('./cypress/fixtures/incidents/temp_prometheus_rule.yaml', yamlContent).then(() => {
31+
// Apply the modified YAML
32+
cy.exec(
33+
`oc apply -f ./cypress/fixtures/incidents/temp_prometheus_rule.yaml --kubeconfig ${kubeconfigPath}`,
34+
);
35+
36+
// Clean up temporary file
37+
cy.exec('rm ./cypress/fixtures/incidents/temp_prometheus_rule.yaml');
38+
});
39+
});
40+
41+
cy.exec(
42+
`oc apply -f ./cypress/fixtures/incidents/pod_crash_loop.yaml --kubeconfig ${kubeconfigPath}`,
43+
);
44+
45+
// Return the alert name for the test to use
46+
return cy.wrap(randomAlertName);
47+
});
48+
49+
// Clean up incident fixture manifests from the cluster
50+
Cypress.Commands.add('cleanupIncidentPrometheusRules', () => {
51+
const kubeconfigPath = Cypress.env('KUBECONFIG_PATH');
52+
53+
// Delete all PrometheusRules that match our pattern (kubernetes-monitoring-podcrash-rules)
54+
// This ensures cleanup before tests and after tests
55+
cy.exec(
56+
`oc delete prometheusrule kubernetes-monitoring-podcrash-rules -n openshift-monitoring --kubeconfig ${kubeconfigPath} --ignore-not-found=true`,
57+
);
58+
59+
// Clear the environment variable if it exists
60+
if (Cypress.env('CURRENT_ALERT_NAME')) {
61+
Cypress.env('CURRENT_ALERT_NAME', null);
62+
}
63+
64+
cy.executeAndDelete(
65+
`oc delete -f ./cypress/fixtures/incidents/pod_crash_loop.yaml --ignore-not-found=true --kubeconfig ${kubeconfigPath}`,
66+
);
67+
});
68+

0 commit comments

Comments
 (0)