@@ -23,8 +23,17 @@ import {
2323 ExtensionCardPage ,
2424 RunnerOptions ,
2525 test ,
26+ ResourceConnectionCardPage ,
27+ startChromium ,
28+ findPageWithTitleInBrowser ,
29+ ConfirmInputValue ,
30+ KubeContextPage ,
31+ performBrowserLogin ,
2632} from '@podman-desktop/tests-playwright' ;
2733import { DeveloperSandboxPage } from './model/pages/developer-sandbox-page' ;
34+ import { CreateResourcePage } from './model/pages/create-resource-page' ;
35+ import type { Browser , BrowserContext , Page } from '@playwright/test' ;
36+ import path , { join } from 'node:path' ;
2837
2938let extensionInstalled = false ;
3039let extensionCard : ExtensionCardPage ;
@@ -37,6 +46,11 @@ const activeExtensionStatus = 'ACTIVE';
3746const disabledExtensionStatus = 'DISABLED' ;
3847const activeConnectionStatus = 'RUNNING' ;
3948const skipInstallation = process . env . SKIP_INSTALLATION === 'true' ;
49+ let browserOutputPath : string ;
50+ let loginCommand = '' ;
51+ const resourceCardLabel = 'redhat.sandbox' ;
52+ const contextName = 'dev-sandbox-context-3' ;
53+ const chromePort = '9222' ;
4054
4155test . use ( {
4256 runnerOptions : new RunnerOptions ( { customFolder : 'sandbox-tests-pd' , autoUpdate : false , autoCheckUpdates : false } ) ,
@@ -45,6 +59,8 @@ test.beforeAll(async ({ runner, page, welcomePage }) => {
4559 runner . setVideoAndTraceName ( 'sandbox-e2e' ) ;
4660 await welcomePage . handleWelcomePage ( true ) ;
4761 extensionCard = new ExtensionCardPage ( page , extensionLabelName , extensionLabel ) ;
62+ browserOutputPath = test . info ( ) . project . outputDir ;
63+ console . log ( `Saving browser test artifacts to: '${ browserOutputPath } '` ) ;
4864} ) ;
4965
5066test . afterAll ( async ( { runner } ) => {
@@ -140,6 +156,161 @@ test.describe.serial('Red Hat Developer Sandbox extension verification', () => {
140156 } ) ;
141157 } ) ;
142158
159+ test . describe . serial ( 'Developer Sandbox cluster verification' , async ( ) => {
160+ test . describe . serial ( 'Fetch login command via browser' , async ( ) => {
161+ let chromiumPage : Page | undefined ;
162+ let browser : Browser | undefined ;
163+ let context : BrowserContext | undefined ;
164+
165+ test . afterAll ( async ( ) => {
166+ if ( browser ) {
167+ console . log ( 'Stopping tracing and closing browser...' ) ;
168+ await context ?. tracing . stop ( { path : join ( path . join ( browserOutputPath ) , 'traces' , 'browser-sandbox-trace.zip' ) } ) ;
169+ if ( chromiumPage ) {
170+ await chromiumPage . close ( ) ;
171+ }
172+ await browser . close ( ) ;
173+ }
174+ } ) ;
175+
176+ test ( 'Open Developer Sandbox page in browser' , async ( { navigationBar, page } ) => {
177+ test . setTimeout ( 120_000 ) ;
178+ //get sandbox url
179+ const settingsBar = await navigationBar . openSettings ( ) ;
180+ await settingsBar . resourcesTab . click ( ) ;
181+ const resourcesPage = new ResourcesPage ( page ) ;
182+ playExpect ( await resourcesPage . resourceCardIsVisible ( resourceCardLabel ) ) . toBeTruthy ( ) ;
183+ await resourcesPage . goToCreateNewResourcePage ( resourceCardLabel ) ;
184+ const createResourcePage = new CreateResourcePage ( page ) ;
185+ await createResourcePage . logIntoSandboxButton . click ( ) ;
186+ const websiteDialog = createResourcePage . content . getByRole ( 'dialog' , { name : 'Open External Website' } ) ;
187+ await playExpect ( websiteDialog ) . toBeVisible ( ) ;
188+ const sandboxUrl = await websiteDialog . getByLabel ( 'Dialog Details' ) . textContent ( ) ;
189+ const cancelDialogButton = websiteDialog . getByRole ( 'button' , { name : 'Cancel' } ) ;
190+ await cancelDialogButton . click ( ) ;
191+
192+ //open the website
193+ if ( sandboxUrl ) {
194+ browser = await startChromium ( chromePort , path . join ( browserOutputPath ) ) ;
195+ context = await browser . newContext ( ) ;
196+ await context . tracing . start ( { screenshots : true , snapshots : true , sources : true } ) ;
197+ const newPage = await context . newPage ( ) ;
198+ await newPage . goto ( sandboxUrl ) ;
199+ await newPage . waitForURL ( / d e v e l o p e r s .r e d h a t .c o m / ) ;
200+ chromiumPage = newPage ;
201+ if ( browser ) {
202+ await findPageWithTitleInBrowser ( browser , 'Developer Sandbox | Red Hat Developer' ) ;
203+ }
204+ console . log ( `Found page with title: ${ await chromiumPage ?. title ( ) } ` ) ;
205+ } else {
206+ throw new Error ( 'Did not find Developer Sandbox page' ) ;
207+ }
208+ } ) ;
209+ test ( 'Log into Red Hat Sandbox' , async ( ) => {
210+ //go to login page
211+ playExpect ( chromiumPage ) . toBeDefined ( ) ;
212+ if ( ! chromiumPage ) {
213+ throw new Error ( 'Chromium browser page was not initialized' ) ;
214+ }
215+ await chromiumPage . bringToFront ( ) ;
216+ console . log ( `Switched to Chrome tab with title: ${ await chromiumPage . title ( ) } ` ) ;
217+ const startSandboxButton = chromiumPage . getByRole ( 'button' , { name : 'Start your sandbox for free' } ) ;
218+ await playExpect ( startSandboxButton ) . toBeVisible ( ) ;
219+ await startSandboxButton . click ( ) ;
220+
221+ //log in, same tab
222+ const usernameAction : ConfirmInputValue = {
223+ inputLocator : chromiumPage . getByRole ( 'textbox' , { name : 'username' } ) ,
224+ inputValue : process . env . DVLPR_USERNAME ?? 'unknown' ,
225+ confirmLocator : chromiumPage . getByRole ( 'button' , { name : 'Next' } ) ,
226+ } ;
227+ const passwordAction : ConfirmInputValue = {
228+ inputLocator : chromiumPage . getByRole ( 'textbox' , { name : 'password' } ) ,
229+ inputValue : process . env . DVLPR_PASSWORD ?? 'unknown' ,
230+ confirmLocator : chromiumPage . getByRole ( 'button' , { name : 'Log in' } ) ,
231+ } ;
232+ const usernameBox = chromiumPage . getByRole ( 'textbox' , { name : 'Red Hat login' } ) ;
233+ await playExpect ( usernameBox ) . toBeVisible ( { timeout : 5_000 } ) ;
234+ await usernameBox . focus ( ) ;
235+
236+ //after login redirect twice to sandbox.redhat.com, same tab
237+ await performBrowserLogin ( chromiumPage , / L o g I n / , usernameAction , passwordAction , async ( chromiumPage ) => {
238+ playExpect ( chromiumPage ) . toBeDefined ( ) ;
239+ if ( ! chromiumPage ) {
240+ throw new Error ( 'Chromium browser page was not initialized' ) ;
241+ }
242+ playExpect ( await chromiumPage . title ( ) ) . toBe ( 'Developer Sandbox | Developer Sandbox' ) ;
243+ await chromiumPage . screenshot ( { path : join ( path . join ( browserOutputPath ) , 'screenshots' , 'after_login_in_browser.png' ) , type : 'png' , fullPage : true } ) ;
244+ } ) ;
245+ } ) ;
246+ test ( 'Fetch the login command' , async ( ) => {
247+ //open "try it" openshift
248+ playExpect ( chromiumPage ) . toBeDefined ( ) ;
249+ if ( ! chromiumPage ) {
250+ throw new Error ( 'Chromium browser page was not initialized' ) ;
251+ }
252+ await chromiumPage . bringToFront ( ) ;
253+ const openshiftBoxLabel = chromiumPage . getByAltText ( 'Openshift' , { exact : true } ) ;
254+ await playExpect ( openshiftBoxLabel ) . toBeVisible ( ) ;
255+ const openshiftBox = openshiftBoxLabel . locator ( '..' ) . locator ( '..' ) . locator ( '..' ) ;
256+ const tryItButton = openshiftBox . getByRole ( 'button' , { name : 'Try it' } ) ;
257+ await playExpect ( tryItButton ) . toBeVisible ( ) ;
258+ await tryItButton . click ( ) ;
259+
260+ //new tab, log in through the Openshift auth page (sometimes might need reload)
261+ await loginThroughOpenshiftServicePage ( browser ! , chromiumPage ) ;
262+
263+ //same tab, get login command from the Console Openshift page
264+ const userDropdownMenuButton = chromiumPage . getByRole ( 'button' , { name : 'User menu' } ) ;
265+ await playExpect ( userDropdownMenuButton ) . toBeVisible ( { timeout : 50_000 } ) ;
266+ await userDropdownMenuButton . click ( ) ;
267+ const copyLoginCommandButton = chromiumPage . getByText ( 'Copy login command' ) ;
268+ await playExpect ( copyLoginCommandButton ) . toBeVisible ( ) ;
269+ await copyLoginCommandButton . click ( ) ;
270+
271+ //new tab, find command (sandbox login might need reload)
272+ await loginThroughOpenshiftServicePage ( browser ! , chromiumPage ) ;
273+
274+ const displayTokenButton = chromiumPage . getByRole ( 'button' , { name : 'Display Token' } ) ;
275+ await playExpect ( displayTokenButton ) . toBeVisible ( ) ;
276+ await displayTokenButton . click ( ) ;
277+ const commandElement = chromiumPage . getByText ( 'oc login' ) . locator ( '..' ) ;
278+ await playExpect ( commandElement ) . toBeVisible ( ) ;
279+ loginCommand = await commandElement . innerText ( ) ;
280+ } ) ;
281+ } ) ;
282+
283+ test ( 'Create Sandbox cluster' , async ( { page } ) => {
284+ await page . bringToFront ( ) ;
285+ const createResourcePage = new CreateResourcePage ( page ) ;
286+ await createResourcePage . createResource ( loginCommand , contextName ) ;
287+ } ) ;
288+
289+ test ( 'Verify Sandbox cluster and context' , async ( { page, navigationBar } ) => {
290+ const sandboxClusterCard = new ResourceConnectionCardPage ( page , resourceCardLabel , contextName ) ;
291+ playExpect ( await sandboxClusterCard . doesResourceElementExist ( ) ) . toBeTruthy ( ) ;
292+ await playExpect ( sandboxClusterCard . resourceElementConnectionStatus ) . toHaveText ( 'RUNNING' ) ;
293+
294+ const settingsBar = await navigationBar . openSettings ( ) ;
295+ await settingsBar . kubernetesTab . click ( ) ;
296+ const kubeContextPage = new KubeContextPage ( page ) ;
297+ playExpect ( await kubeContextPage . pageIsEmpty ( ) ) . not . toBeTruthy ( ) ;
298+ playExpect ( await kubeContextPage . isContextReachable ( contextName ) ) . toBeTruthy ( ) ;
299+ playExpect ( await kubeContextPage . isContextDefault ( contextName ) ) . not . toBeTruthy ( ) ;
300+ } ) ;
301+
302+ test ( 'Delete remote cluster context' , async ( { page, navigationBar } ) => {
303+ const kubeContextPage = new KubeContextPage ( page ) ;
304+ await kubeContextPage . deleteContext ( contextName ) ;
305+ playExpect ( await kubeContextPage . pageIsEmpty ( ) ) . toBeTruthy ( ) ;
306+
307+ const settingsBar = await navigationBar . openSettings ( ) ;
308+ await settingsBar . resourcesTab . click ( ) ;
309+ const sandboxClusterCard = new ResourceConnectionCardPage ( page , resourceCardLabel , contextName ) ;
310+ playExpect ( await sandboxClusterCard . doesResourceElementExist ( ) ) . not . toBeTruthy ( ) ;
311+ } ) ;
312+ } ) ;
313+
143314 test ( 'Extension can be removed' , async ( { navigationBar } ) => {
144315 await removeExtension ( navigationBar ) ;
145316 } ) ;
@@ -184,3 +355,14 @@ async function checkSandboxInDashboard(navigationBar: NavigationBar, isInstalled
184355 await playExpect ( sandboxProviderCard ) . toBeHidden ( ) ;
185356 }
186357}
358+
359+ async function loginThroughOpenshiftServicePage ( browser : Browser , chromiumPage : Page ) {
360+ let loginSandboxPage = await findPageWithTitleInBrowser ( browser ! , 'Login - Red Hat OpenShift Service on AWS' ) ;
361+ if ( ! loginSandboxPage ) {
362+ throw new Error ( 'Sandbox service login browser page was not initialized' ) ;
363+ }
364+ await loginSandboxPage . bringToFront ( ) ;
365+ const loginWithSandboxButton = chromiumPage . getByRole ( 'button' , { name : 'Log in with DevSandbox' } ) ;
366+ await playExpect ( loginWithSandboxButton ) . toBeVisible ( ) ;
367+ await loginWithSandboxButton . click ( ) ;
368+ }
0 commit comments