Skip to content

Commit 629dc7b

Browse files
authored
test: enable video recording for UI E2E tests (codeready-toolchain#1265)
* test: enable video recording for UI E2E tests * improvements * requested changes * improve comment * improve comment * requested changes * fix * mask username field
1 parent ea125f1 commit 629dc7b

8 files changed

Lines changed: 89 additions & 21 deletions

File tree

make/devsandbox-dashboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,5 @@ endif
9797
-e QUAY_NAMESPACE=$(QUAY_NAMESPACE) \
9898
-e DEPLOY_UI=true \
9999
-e PUBLISH_UI=false \
100+
-e RUNNING_IN_CONTAINER=true \
100101
$(E2E_TEST_IMAGE_NAME) make test-devsandbox-dashboard-e2e

test/e2e/devsandbox-dashboard/activities_page_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import (
1212

1313
// TestActivitiesPage opens and verifies that activities cards links are not broken
1414
func TestActivitiesPage(t *testing.T) {
15-
page := sandboxui.Setup(t, "test-activities-page")
15+
testName := "test-activities-page"
16+
page := sandboxui.Setup(t, testName)
1617

1718
// navigate to 'Activities' link
1819
activitiesLink := page.GetByRole("link", playwright.PageGetByRoleOptions{
@@ -40,7 +41,7 @@ func TestActivitiesPage(t *testing.T) {
4041
Level: playwright.Int(5),
4142
})
4243

43-
//wait for the 6th card (index 5) to appear - if it's there, all 6 are loaded
44+
// wait for the 6th card (index 5) to appear - if it's there, all 6 are loaded
4445
err = cards.Nth(5).WaitFor()
4546
require.NoError(t, err)
4647

@@ -56,7 +57,7 @@ func TestActivitiesPage(t *testing.T) {
5657
require.NoError(t, err)
5758

5859
// open the article in a new popup and wait for it to fully load
59-
popup, err := sandboxui.ClickAndWaitForPopup(page, article)
60+
popup, err := sandboxui.ClickAndWaitForPopup(t, page, article, testName)
6061
require.NoError(t, err)
6162

6263
// assert the popup heading matches the expected article title

test/e2e/devsandbox-dashboard/fresh_signup_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ import (
2121
// 3. Accessing OpenShift after signup
2222
func TestFreshSignup(t *testing.T) {
2323
// Step 1: Setup the browser and login (LoadConfig called inside Setup)
24-
page := sandboxui.Setup(t, "test-fresh-signup")
24+
testName := "test-fresh-signup"
25+
page := sandboxui.Setup(t, testName)
2526

2627
// Ensure the user signup is not present in the system
2728
env := viper.GetString("ENVIRONMENT")
@@ -35,7 +36,7 @@ func TestFreshSignup(t *testing.T) {
3536
performSignup(t, page, env, username)
3637

3738
// Step 4: Verify OpenShift access
38-
verifyDevSandboxAccess(t, page, env)
39+
verifyDevSandboxAccess(t, page, env, testName)
3940
}
4041

4142
func ensureNoUserSignup(t *testing.T, env, username string) {
@@ -155,7 +156,7 @@ func performSignup(t *testing.T, page playwright.Page, env, username string) {
155156
}
156157

157158
// verifyDevSandboxAccess tests access to OpenShift after the user is signed up
158-
func verifyDevSandboxAccess(t *testing.T, page playwright.Page, env string) {
159+
func verifyDevSandboxAccess(t *testing.T, page playwright.Page, env, testName string) {
159160
imgName := "Red Hat OpenShift Service on"
160161
logMessage := "Log in with…"
161162
if env == sandboxui.TestEnv {
@@ -183,7 +184,7 @@ func verifyDevSandboxAccess(t *testing.T, page playwright.Page, env string) {
183184
sandboxui.IsVisible(t, tryItBtn)
184185

185186
// open the "Try it" button in a new popup and wait for it to fully load
186-
devSandboxPage, err := sandboxui.ClickAndWaitForPopup(page, tryItBtn)
187+
devSandboxPage, err := sandboxui.ClickAndWaitForPopup(t, page, tryItBtn, testName)
187188
require.NoError(t, err)
188189

189190
img := devSandboxPage.GetByRole("img", playwright.PageGetByRoleOptions{

test/e2e/devsandbox-dashboard/header_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@ import (
1212
// TestHeader opens and verifies that 'Red Hat Developer Hub'
1313
// and 'Contact Red Hat Sales' links are not broken
1414
func TestHeader(t *testing.T) {
15-
page := sandboxui.Setup(t, "test-header")
15+
testName := "test-header"
16+
page := sandboxui.Setup(t, testName)
1617

1718
// opens and verifies that 'Red Hat Developer Hub' popup is not broken
1819
rhdhLink := page.GetByRole("link", playwright.PageGetByRoleOptions{
1920
Name: "Red Hat Developer Hub , Opens",
2021
})
2122
sandboxui.IsVisible(t, rhdhLink)
2223

23-
rhdhPage, err := sandboxui.ClickAndWaitForPopup(page, rhdhLink)
24+
rhdhPage, err := sandboxui.ClickAndWaitForPopup(t, page, rhdhLink, testName)
2425
require.NoError(t, err)
2526

2627
h1Text, err := rhdhPage.Locator("h1").TextContent()
@@ -33,7 +34,7 @@ func TestHeader(t *testing.T) {
3334
salesBtn := page.GetByRole("button", playwright.PageGetByRoleOptions{
3435
Name: "Contact Red Hat Sales",
3536
})
36-
salesPage, err := sandboxui.ClickAndWaitForPopup(page, salesBtn)
37+
salesPage, err := sandboxui.ClickAndWaitForPopup(t, page, salesBtn, testName)
3738
require.NoError(t, err)
3839

3940
h1Text, err = salesPage.Locator("h1").TextContent()

testsupport/devsandbox-dashboard/login.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,11 @@ func (lp *LoginPage) Navigate(t *testing.T, url string) {
6464
}
6565

6666
func (lp *LoginPage) Login(t *testing.T, loginUsername, loginPw string) {
67-
err := lp.LoginUsernameLoc.Fill(loginUsername)
67+
// Mask username field
68+
_, err := lp.LoginUsernameLoc.Evaluate(`element => element.style.webkitTextSecurity = 'disc'`, nil)
69+
require.NoError(t, err)
70+
71+
err = lp.LoginUsernameLoc.Fill(loginUsername)
6872
require.NoError(t, err)
6973

7074
if lp.Env == DevEnv {

testsupport/devsandbox-dashboard/popup.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ package sandboxui
33
import (
44
"context"
55
"fmt"
6+
"path/filepath"
67
"strings"
8+
"testing"
79
"time"
810

911
"github.com/playwright-community/playwright-go"
1012
"k8s.io/apimachinery/pkg/util/wait"
1113
)
1214

13-
func ClickAndWaitForPopup(currentPage playwright.Page, locator playwright.Locator) (playwright.Page, error) {
15+
func ClickAndWaitForPopup(t *testing.T, currentPage playwright.Page, locator playwright.Locator, testName string) (playwright.Page, error) {
1416
var popup playwright.Page
1517
var err error
1618

@@ -40,5 +42,9 @@ func ClickAndWaitForPopup(currentPage playwright.Page, locator playwright.Locato
4042
if waitErr != nil {
4143
return nil, fmt.Errorf("popup did not finish loading: %w", waitErr)
4244
}
45+
46+
targetVideoPath := filepath.Join(getTraceDirectory(t), fmt.Sprintf("%s-popup.webm", testName))
47+
handleRecordedVideo(t, popup, targetVideoPath)
48+
4349
return popup, nil
4450
}

testsupport/devsandbox-dashboard/setup.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package sandboxui
22

33
import (
4+
"fmt"
45
"path/filepath"
56
"runtime"
67
"sync"
@@ -53,6 +54,11 @@ func Setup(t *testing.T, testName string) playwright.Page {
5354
opts.IgnoreHttpsErrors = playwright.Bool(true)
5455
}
5556

57+
traceDirectory := getTraceDirectory(t)
58+
opts.RecordVideo = &playwright.RecordVideo{
59+
Dir: traceDirectory,
60+
}
61+
5662
context, err := browser.NewContext(opts)
5763
require.NoError(t, err)
5864

@@ -62,6 +68,8 @@ func Setup(t *testing.T, testName string) playwright.Page {
6268
page, err := context.NewPage()
6369
require.NoError(t, err)
6470

71+
handleRecordedVideo(t, page, filepath.Join(traceDirectory, fmt.Sprintf("%s.webm", testName)))
72+
6573
login := NewLoginPage(page, env)
6674
login.Navigate(t, baseURL)
6775

testsupport/devsandbox-dashboard/trace.go

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"os"
66
"path/filepath"
7+
"strings"
78
"testing"
89

910
"github.com/playwright-community/playwright-go"
@@ -20,27 +21,72 @@ func trace(t *testing.T, context playwright.BrowserContext, testName string) {
2021
})
2122
require.NoError(t, err)
2223

24+
tracePath := filepath.Join(getTraceDirectory(t), fmt.Sprintf("trace-%s.zip", testName))
25+
26+
t.Cleanup(func() {
27+
if t.Failed() {
28+
if err := context.Tracing().Stop(tracePath); err != nil {
29+
t.Logf("failed to save trace: %v", err)
30+
} else {
31+
t.Logf("saved trace to %s", tracePath)
32+
}
33+
}
34+
})
35+
}
36+
37+
func getTraceDirectory(t *testing.T) string {
2338
dir, err := os.Getwd()
2439
require.NoError(t, err)
25-
tracePath := filepath.Join(dir, "..", "..", "trace", fmt.Sprintf("trace-%s.zip", testName))
40+
41+
dirName := "trace"
42+
getTraceDirectoryPath := filepath.Join(dir, "..", "..", dirName)
2643

2744
if os.Getenv("RUNNING_IN_CONTAINER") == "true" {
28-
tracePath = filepath.Join(os.Getenv("E2E_REPO_PATH"), "trace", fmt.Sprintf("trace-%s.zip", testName))
45+
getTraceDirectoryPath = filepath.Join(os.Getenv("E2E_REPO_PATH"), dirName)
2946
}
3047

31-
if os.Getenv("CI") == "true" {
48+
// Use ARTIFACT_DIR if set (CI environment)
49+
if artifactDir := os.Getenv("ARTIFACT_DIR"); artifactDir != "" {
3250
// save trace in the job CI artifact directory
33-
// artifacts/e2e/test/artifacts/devsandbox-dashboard/trace/trace-%s.zip
34-
tracePath = filepath.Join(os.Getenv("ARTIFACT_DIR"), "devsandbox-dashboard", "trace", fmt.Sprintf("trace-%s.zip", testName))
51+
// artifacts/e2e/test/artifacts/devsandbox-dashboard/trace
52+
getTraceDirectoryPath = filepath.Join(artifactDir, "devsandbox-dashboard", dirName)
3553
}
3654

55+
return getTraceDirectoryPath
56+
}
57+
58+
// handleRecordedVideo manages recorded videos for main pages and popups:
59+
// - On test failure: renames videos from auto-generated IDs to test names (popups include UUID suffix)
60+
// - On test success: removes videos
61+
func handleRecordedVideo(t *testing.T, page playwright.Page, targetVideoPath string) {
3762
t.Cleanup(func() {
63+
videoPath, err := page.Video().Path()
64+
if err != nil || videoPath == "" {
65+
t.Logf("failed to resolve video path %s: %v", videoPath, err)
66+
return
67+
}
68+
69+
// Handle failed test - rename video
3870
if t.Failed() {
39-
if err := context.Tracing().Stop(tracePath); err != nil {
40-
t.Logf("failed to save trace: %v", err)
41-
} else {
42-
t.Logf("saved trace to %s", tracePath)
71+
// For popup videos, rename with UUID to avoid conflicts when multiple popups exist in the same test
72+
if strings.Contains(targetVideoPath, "popup") {
73+
uuid := filepath.Base(videoPath)
74+
uuid = strings.TrimSuffix(uuid, ".webm")
75+
if len(uuid) > 8 {
76+
uuid = uuid[:8] // Truncate to first 8 chars
77+
}
78+
targetVideoPath = strings.Replace(targetVideoPath, "popup", fmt.Sprintf("popup-%s", uuid), 1)
79+
}
80+
81+
if err := os.Rename(videoPath, targetVideoPath); err != nil {
82+
t.Logf("failed to rename video %s: %v", videoPath, err)
4383
}
84+
return
85+
}
86+
87+
// Test passed - remove video
88+
if err := os.Remove(videoPath); err != nil {
89+
t.Logf("failed to remove video %s: %v", videoPath, err)
4490
}
4591
})
4692
}

0 commit comments

Comments
 (0)