diff --git a/Jenkinsfile.public b/Jenkinsfile.public index f6dfe7cd1..f0f3219b9 100644 --- a/Jenkinsfile.public +++ b/Jenkinsfile.public @@ -364,7 +364,7 @@ pipeline { steps { sh 'psql -U postgres -c \'create database testui;\'' catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { - sh 'cd testsuite && go test -parallel 1 -p 1 -vet=off -timeout 32m -json -race ./... 2>&1 | tee ../.build/ui-tests.json | xunit -out ../.build/ui-tests.xml' + sh 'cd testsuite && go test -parallel 1 -p 1 -short -vet=off -timeout 32m -json -race ./... 2>&1 | tee ../.build/ui-tests.json | xunit -out ../.build/ui-tests.xml' } } post { diff --git a/testsuite/ui/satellite/browser_features_test.go b/testsuite/ui/satellite/browser_features_test.go new file mode 100644 index 000000000..575fb5e2f --- /dev/null +++ b/testsuite/ui/satellite/browser_features_test.go @@ -0,0 +1,249 @@ +// Copyright (C) 2021 Storj Labs, Inc. +// See LICENSE for copying information. + +package satellite_test + +import ( + "fmt" + "testing" + + "github.com/go-rod/rod" + "github.com/stretchr/testify/require" + + "storj.io/common/testcontext" + "storj.io/storj/testsuite/ui/uitest" +) + +func TestBrowserFeatures(t *testing.T) { + uitest.Edge(t, func(t *testing.T, ctx *testcontext.Context, planet *uitest.EdgePlanet, browser *rod.Browser) { + page := openPage(browser, planet.Satellites[0].ConsoleURL()) + + // Sign up and login. + signUpWithUser(t, planet, page) + loginWithUser(t, planet, page) + + // Navigate into browser with new onboarding. + page.MustElementR("a", "Skip and go directly to dashboard").MustClick() + page.MustElementR("p", "Objects").MustClick() + page.MustElementR("label", "I understand, and I have saved the passphrase.").MustClick() + page.MustElementR("span", "Next >").MustClick() + + // Verify that browser component has loaded and that the dropzone is present. + page.MustElementR("p", "Drop Files Here to Upload") + + // Attempt to create an invalid folder. + page.MustElementR("button", "New Folder").MustClick() + folderInput := page.MustElement("[placeholder=\"Name of the folder\"]") + folderInput.MustInput("...") + page.MustElementR("button", "Save Folder").MustProperty("disabled") + require.Equal(t, "...", folderInput.MustText(), "Folder input does not contain the `...` invalid name") + + // Create a folder. + err := folderInput.SelectAllText() + require.NoError(t, err) + + folderInput.MustInput("folderCreatedThroughInput") + page.MustElementR("button", "Save Folder").MustClick() + page.MustElementR("[aria-roledescription=folder]", "folderCreatedThroughInput") + + // Navigate into the folder and make sure the dropzone is visible. + page.MustElementR("[aria-roledescription=folder]", "folderCreatedThroughInput").MustClick() + require.Equal(t, " folderCreatedThroughInput", page.MustElement("a[aria-current=\"page\"]").MustText(), "Navigating into the folder `folderCreatedThroughInput` has not been successful") + page.MustElementR("p", "Drop Files Here to Upload") + + // Attempt to create a new folder but cancel. + page.MustElementR("button", "New Folder").MustClick() + page.MustElement("[placeholder=\"Name of the folder\"]").MustInput("Hello World!") + page.MustElementR("button", "Cancel").MustClick() + + // Add a file into folder and check that dropzone is still visible. + wait := page.MustWaitRequestIdle() + page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/img.png") + wait() + page.MustElementR("span", "folderCreatedThroughInput/img.png") + page.MustElement("#close-modal").MustClick() + page.MustElementR("[aria-roledescription=file]", "img.png") + page.MustElementR("p", "Drop Files Here to Upload") + + // Click on the file name. + page.MustElementR("[aria-roledescription=file]", "img.png").MustClick() + require.Contains(t, page.MustElement("[aria-roledescription=image-preview]").MustProperty("src").Str(), "img.png", "The modal did not open on file click") + + // Share a file. + page.MustElementR("span", "Share").MustClick() + page.MustElement("#generateShareLink") + page.MustElement("#close-modal").MustClick() + + // Click on the hamburger and share. + page.MustElement("button[aria-roledescription=dropdown]").MustClick() + page.MustElementR("button", "Share").MustClick() + page.MustElement("#btn-copy-link") + page.MustElement("[aria-roledescription=close-share-modal]").MustClick() + + // Click on the hamburger and then details. + page.MustElement("button[aria-roledescription=dropdown]").MustClick() + page.MustElementR("button", "Details").MustClick() + require.Contains(t, page.MustElement("[aria-roledescription=image-preview]").MustProperty("src").Str(), "img.png", "The dropdown details functionality is not working") + page.MustElementR("span", "Share").MustClick() + page.MustElement("#generateShareLink") + page.MustElement("#close-modal").MustClick() + + // Use the `..` to navigate out of the folder. + page.MustElement("#navigate-back").MustClick() + page.MustElementR("a[aria-current=page]", "demo-bucket") + + // Add another folder. + page.MustElementR("button", "New Folder").MustClick() + page.MustElement("[placeholder=\"Name of the folder\"]").MustInput("go-rod-test3") + page.MustElementR("button", "Save Folder").MustClick() + page.MustElementR("[aria-roledescription=folder]", "go-rod-test3") + + // Add two files. + page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/img2.png") + page.MustElement("#close-modal").MustClick() + page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/img.png") + page.MustElementR("[aria-roledescription=file]", "img2.png") + page.MustElementR("[aria-roledescription=file]", "img.png") + + // Sort folders/files (by name, size, and date). + require.Equal(t, " folderCreatedThroughInput", page.MustElement("table > tbody > tr:nth-child(1) > td").MustText(), "The automatic sorting by name for folders is not working") + require.Equal(t, " img.png", page.MustElement("table > tbody > tr:nth-child(3) > td").MustText(), "The automatic sorting by name for files is not working") + page.MustElementR("th", "Name").MustClick() + require.Equal(t, " go-rod-test3", page.MustElement("table > tbody > tr:nth-child(1) > td").MustText(), "Sorting by name is not working for folders") + require.Equal(t, " img2.png", page.MustElement("table > tbody > tr:nth-child(3) > td").MustText(), "Sorting by name is not working for files") + // sort by size and date still left to do. + + // Single folder select. + page.MustElement("table > tbody > tr:nth-child(1)").MustClick() + require.Contains(t, page.MustElement("table > tbody > tr:nth-child(1)").String(), ".selected-row", "The clicked folder row has not been selected properly") + + // Multifolder unselect. + page.MustElement("button[aria-roledescription=dropdown]").MustClick() + page.MustElement("button[aria-roledescription=dropdown]").MustClick() + require.Equal(t, "false", fmt.Sprint(page.MustElement("table > tbody > tr:nth-child(1)").MustHas(".selected-row")), "Multiple selected folders were not unselected successfully") + + // Single file select. + page.MustElement("table > tbody > tr:nth-child(3)").MustClick() + require.Contains(t, page.MustElement("table > tbody > tr:nth-child(3)").String(), ".selected-row", "Single file select is not working properly") + // Multifile select **CAN'T SIMULATE MULTIPLE FILE SELECT YET**. + + // Multifile unselect. + page.MustElement("button[aria-roledescription=dropdown]").MustClick() + page.MustElement("button[aria-roledescription=dropdown]").MustClick() + require.Equal(t, "false", fmt.Sprint(page.MustElement("table > tbody > tr:nth-child(3)").MustHas(".selected-row")), "Multiple selected files were not unselected successfully") + + // Select file and folders **CAN'T SIMULATE MULTIPLE FILE/FOLDERS SELECT YET**. + + // Navigate into folders and use the breadcrumbs to navigate out. + page.MustElementR("[aria-roledescription=folder]", "go-rod-test3").MustClick() + page.MustElement("#navigate-back").MustClick() + page.MustElementR("a[aria-current=page]", "demo-bucket") + + // Cancel folder deletion by way of hamburger. + page.MustElement("button[aria-roledescription=dropdown]").MustClick() + page.MustElementR("button", "Delete").MustClick() + page.MustElementR("button", "No").MustClick() + page.MustElementR("a", "go-rod-test3") + + // Delete a folder by clicking on hamburger. + page.MustElement("button[aria-roledescription=dropdown]").MustClick() + page.MustElementR("button", "Delete").MustClick() + page.MustElementR("button", "Yes").MustClick() + page.MustElementR("table > tbody > tr:nth-child(1) > td", "folderCreatedThroughInput") + + // Cancel folder deletion by way of trashcan. + page.MustElement("tr[scope=\"row\"]").MustClick() + page.MustElement("#header-delete").MustClick() + page.MustElementR("button", "No").MustClick() + page.MustElementR("a[href=\"/objects/upload/folderCreatedThroughInput/\"]", "folderCreatedThroughInput") + + // Delete a folder by selecting and clicking on trashcan. + page.MustElement("tr[scope=row]").MustClick() + page.MustElement("#header-delete").MustClick() + page.MustElementR("button", "Yes").MustClick() + page.MustElementR("table > tbody > tr:nth-child(1) > td", "img2.png") + + // Cancel file deletion by way of hamburger. + page.MustElement("button[aria-roledescription=dropdown]").MustClick() + page.MustElementR("button", "Delete").MustClick() + page.MustElementR("button", "No").MustClick() + require.Equal(t, " img2.png", page.MustElement("table > tbody > tr:nth-child(1) > td").MustText(), "File deletion cancellation by way of hamburger is not working") + + // Delete a file by clicking on the hamburger. + page.MustElement("button[aria-roledescription=dropdown]").MustClick() + page.MustElementR("button", "Delete").MustClick() + page.MustElementR("button", "Yes").MustClick() + page.MustElementR("table > tbody > tr:nth-child(1) > td", "img.png") + + // Cancel file deletion by way of trashcan. + page.MustElement("tr[scope=row]").MustClick() + page.MustElement("#header-delete").MustClick() + page.MustElementR("button", "No").MustClick() + require.Equal(t, " img.png", page.MustElement("table > tbody > tr:nth-child(1) > td").MustText(), "File cancellation by way of trashcan is not working") + + // Delete a file by clicking on the row and clicking on the trashcan. + wait2 := page.MustWaitRequestIdle() + page.MustElement("tr[scope=row]").MustClick() + page.MustElement("#header-delete").MustClick() + page.MustElementR("button", "Yes").MustClick() + page.MustElementR("p", "Drop Files Here to Upload") + wait2() + + // Delete multiple folders by selection **SELECTION NOT WORKING**. + + // Delete multiple files by selection **SELECTION NOT WORKING**. + + // Empty out entire folder. + + // Attempt to create a folder with spaces. + page.MustElementR("button", "New Folder").MustClick() + page.MustElement("[placeholder=\"Name of the folder\"]").MustInput(" ") + page.MustElementR("button", "Save Folder").MustProperty("disabled") + require.Equal(t, " ", page.MustElement("[placeholder=\"Name of the folder\"]").MustText(), "Folder input does not contain the empty invalid name") + page.MustElementR("button", "Cancel").MustClick() + + // Create Folder with special characters. + page.MustElementR("button", "New Folder").MustClick() + page.MustElement("[placeholder=\"Name of the folder\"]").MustInput("Свобода") + page.MustElementR("button", "Save Folder").MustClick() + page.MustElementR("[aria-roledescription=folder]", "Свобода") + + // Navigate into folder and create another folder of the same name, and check that the dropzone is present. + page.MustElementR("[aria-roledescription=folder]", "Свобода").MustClick() + page.MustElement("[href=\"/objects/upload/Свобода/\"]") + page.MustElementR("p", "Drop Files Here to Upload") + page.MustElementR("button", "New Folder").MustClick() + page.MustElement("[placeholder=\"Name of the folder\"]").MustInput("Свобода") + page.MustElementR("button", "Save Folder").MustClick() + page.MustElementR("[aria-roledescription=folder]", "Свобода") + + // upload a video. + wait3 := page.MustWaitRequestIdle() + page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/movie.mp4") + wait3() + page.MustElementR("span", "Свобода/movie.mp4") + page.MustElement("#close-modal").MustClick() + page.MustElementR("[aria-roledescription=file]", "movie.mp4") + page.MustElementR("[aria-roledescription=file-size]", "1.48 kB") + page.MustElement("[aria-roledescription=file-upload-date]") + page.MustElementR("[aria-roledescription=file]", "movie.mp4").MustClick() + require.Contains(t, page.MustElement("[aria-roledescription=video-preview]").MustProperty("src").Str(), "movie.mp4", "The modal did not open on video file click") + page.MustElement("#close-modal").MustClick() + + // Upload an audio file. + wait4 := page.MustWaitRequestIdle() + page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/audio.mp3") + wait4() + page.MustElementR("[aria-roledescription=file]", "audio.mp3").MustClick() + require.Contains(t, page.MustElement("[aria-roledescription=audio-preview]").MustProperty("src").Str(), "audio.mp3", "The modal did not open on video file click") + page.MustElement("#close-modal").MustClick() + + // Navigate out of nested folder and delete everything. + page.MustElement("#navigate-back").MustClick() + page.MustElement("button[aria-roledescription=dropdown]").MustClick() + page.MustElementR("button", "Delete").MustClick() + wait5 := page.MustWaitRequestIdle() + page.MustElementR("button", "Yes").MustClick() + wait5() + }) +} diff --git a/testsuite/ui/satellite/browser_folder_and_different_file_sizes_upload_test.go b/testsuite/ui/satellite/browser_folder_and_different_file_sizes_upload_test.go new file mode 100644 index 000000000..6249fa996 --- /dev/null +++ b/testsuite/ui/satellite/browser_folder_and_different_file_sizes_upload_test.go @@ -0,0 +1,182 @@ +// Copyright (C) 2021 Storj Labs, Inc. +// See LICENSE for copying information. + +package satellite_test + +import ( + "os" + "testing" + "time" + + "github.com/go-rod/rod" + "github.com/stretchr/testify/require" + + "storj.io/common/memory" + "storj.io/common/testcontext" + "storj.io/storj/testsuite/ui/uitest" +) + +func TestBrowserFolderAndDifferentFileSizesUpload(t *testing.T) { + uitest.Edge(t, func(t *testing.T, ctx *testcontext.Context, planet *uitest.EdgePlanet, browser *rod.Browser) { + page := openPage(browser, planet.Satellites[0].ConsoleURL()) + + // Sign up and login. + signUpWithUser(t, planet, page) + loginWithUser(t, planet, page) + + // Navigate into browser with new onboarding. + page.MustElementR("a", "Skip and go directly to dashboard").MustClick() + page.MustElementR("p", "Objects").MustClick() + page.MustElementR("label", "I understand, and I have saved the passphrase.").MustClick() + page.MustElementR("span", "Next >").MustClick() + + // Verify that browser component has loaded and that the dropzone is present. + page.MustElementR("p", "Drop Files Here to Upload") + + // Create a Folder. + page.MustElementR("button", "New Folder").MustClick() + page.MustElement("[placeholder=\"Name of the folder\"]").MustInput("testing") + page.MustElementR("button", "Save Folder").MustClick() + page.MustElementR("[aria-roledescription=folder]", "testing").MustClick() + + // Attempt to create a folder with spaces. + page.MustElementR("button", "New Folder").MustClick() + page.MustElement("[placeholder=\"Name of the folder\"]").MustInput(" ") + require.Equal(t, "true", page.MustElementR("button", "Save Folder").MustProperty("disabled").Str(), "Folder is not disabled on invalid folder name with spaces") + require.Equal(t, " ", page.MustElement("[placeholder=\"Name of the folder\"]").MustText(), "Folder input does not contain the empty invalid name") + page.MustElementR("button", "Cancel").MustClick() + + // Upload a folder (folder upload doesn't work when headless). + if os.Getenv("STORJ_TEST_SHOW_BROWSER") == "" { + // Create folder + page.MustElementR("button", "New Folder").MustClick() + page.MustElement("[placeholder=\"Name of the folder\"]").MustInput("testData") + page.MustElementR("button", "Save Folder").MustClick() + + // Navigate into folder and upload file. + page.MustElementR("[aria-roledescription=folder]", "testData").MustClick() + page.MustElement("[href=\"/objects/upload/testing/testData/\"]") + page.MustElementR("p", "Drop Files Here to Upload").MustText() + + // Attempt to create a folder with spaces. + page.MustElementR("button", "New Folder").MustClick() + page.MustElement("[placeholder=\"Name of the folder\"]").MustInput(" ") + require.Equal(t, "true", page.MustElementR("button", "Save Folder").MustProperty("disabled").Str(), "Folder is not disabled on invalid folder name with spaces") + require.Equal(t, " ", page.MustElement("[placeholder=\"Name of the folder\"]").MustText(), "Folder input does not contain the empty invalid name") + page.MustElementR("button", "Cancel").MustClick() + + wait := page.MustWaitRequestIdle() + page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/test0bytes.txt") + wait() + page.MustElementR("span", "testing/testData/test0bytes.txt") + page.MustElement("#close-modal").MustClick() + page.MustElementR("[aria-roledescription=file]", "test0bytes.txt").MustClick() + require.Contains(t, page.MustElement("[aria-roledescription=preview-placeholder]").String(), "svg", "The modal did not open upon clicking the test0bytes.txt file") + } else { + wait2 := page.MustWaitRequestIdle() + page.MustElement("input[aria-roledescription=folder-upload]").MustSetFiles("./testdata") + wait2() + page.MustElementR("[aria-roledescription=folder]", "testdata").MustClick() + page.MustElementR("[aria-roledescription=file]", "test0bytes.txt").MustClick() + require.Contains(t, page.MustElement("[aria-roledescription=preview-placeholder]").String(), "svg", "The uploaded folder did not upload the files correctly") + } + + page.MustElement("#close-modal").MustClick() + page.MustElement("#navigate-back").MustClick() + + // Upload duplicate folder (folder upload doesn't work when headless). + if os.Getenv("STORJ_TEST_SHOW_BROWSER") == "" { + // Create folder. + page.MustElementR("button", "New Folder").MustClick() + page.MustElement("[placeholder=\"Name of the folder\"]").MustInput("testdata (1)") + page.MustElementR("button", "Save Folder").MustClick() + + // Navigate into folder and upload file. + page.MustElementR("[aria-roledescription=folder]", "testdata \\(1\\)").MustClick() + page.MustElement("[href=\"/objects/upload/testing/testdata (1)/\"]") + page.MustElementR("p", "Drop Files Here to Upload") + + // Attempt to create a folder with spaces. + page.MustElementR("button", "New Folder").MustClick() + page.MustElement("[placeholder=\"Name of the folder\"]").MustInput(" ") + require.Equal(t, "true", page.MustElementR("button", "Save Folder").MustProperty("disabled").Str(), "Folder is not disabled on invalid folder name with spaces") + require.Equal(t, " ", page.MustElement("[placeholder=\"Name of the folder\"]").MustText(), "Folder input does not contain the empty invalid name") + page.MustElementR("button", "Cancel").MustClick() + + wait3 := page.MustWaitRequestIdle() + page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/test0bytes.txt") + wait3() + page.MustElementR("span", "testing/testdata \\(1\\)/test0bytes.txt") + page.MustElement("#close-modal").MustClick() + page.MustElementR("[aria-roledescription=file]", "test0bytes.txt").MustClick() + require.Contains(t, page.MustElement("[aria-roledescription=preview-placeholder]").String(), "svg", "The modal did not open upon clicking the test0bytes.txt file") + } else { + wait4 := page.MustWaitRequestIdle() + page.MustElement("input[aria-roledescription=folder-upload]").MustSetFiles("./testdata") + wait4() + page.MustElementR("table > tbody > tr:nth-child(1) > td", "..") + page.MustElementR("[aria-roledescription=folder]", "testdata \\(1\\)").MustClick() + page.MustElementR("[aria-roledescription=file]", "test0bytes.txt").MustClick() + require.Contains(t, page.MustElement("[aria-roledescription=preview-placeholder]").String(), "svg", "The uploaded folder did not upload the files correctly") + } + + page.MustElement("#close-modal").MustClick() + page.MustElement("#navigate-back").MustClick() + + // Upload a 0 byte file. + page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/test0bytes.txt") + page.MustElementR("span", "testing/test0bytes.txt") + page.MustElement("#close-modal").MustClick() + page.MustElementR("[aria-roledescription=file]", "test0bytes.txt").MustClick() + require.Contains(t, page.MustElement("[aria-roledescription=preview-placeholder]").String(), "svg", "The modal did not open upon clicking the 0 byte file") + page.MustElement("#close-modal").MustClick() + + // Upload duplicate 0 byte file. + page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/test0bytes.txt") + page.MustElementR("[aria-roledescription=file]", "test0bytes \\(1\\).txt").MustClick() + require.Contains(t, page.MustElement("[aria-roledescription=preview-placeholder]").String(), "svg", "The modal did not open upon clicking the duplicate file") + page.MustElement("#close-modal").MustClick() + + if !testing.Short() { + slowpage := page.Sleeper(uitest.MaxDuration(20 * time.Second)) + + // Upload a 50 MB file. + testFile := generateEmptyFile(t, ctx, "testFile", 5*memory.MiB) + wait5 := slowpage.MustWaitRequestIdle() + slowpage.MustElement("input[aria-roledescription=file-upload]").MustSetFiles(testFile) + wait5() + slowpage.MustElementR("[aria-roledescription=file]", "testFile").MustClick() + require.Contains(t, slowpage.MustElement("[aria-roledescription=preview-placeholder]").String(), "svg", "The modal did not open upon clicking the 50 MB file") + slowpage.MustElement("#close-modal").MustClick() + + // Attempt to upload a large file and cancel the upload after a few segments have been uploaded successfully. + testFile2 := generateEmptyFile(t, ctx, "testFile2", 130*memory.MiB) + slowpage.MustElement("input[aria-roledescription=file-upload]").MustSetFiles(testFile2) + require.Equal(t, " testing/testFile2", slowpage.MustElement("[aria-roledescription=file-uploading]").MustText(), "The testFile2 file has not started uploading") + slowpage.MustElementR("[aria-roledescription=files-uploading-count]", "1 file waiting to be uploaded...") + slowpage.MustElementR("[aria-roledescription=progress-bar]", "1") + slowpage.MustElementR("button", "Cancel").MustClick() + slowpage.MustElementR("table > tbody > tr:nth-child(6) > td > span", "testFile") + slowpage.MustElementR("[aria-roledescription=file]", "testFile").MustClick() + slowpage.MustElement("#close-modal").MustClick() + + // Upload a 130MB file. + wait6 := slowpage.MustWaitRequestIdle() + slowpage.MustElement("input[aria-roledescription=file-upload]").MustSetFiles(testFile2) + require.Equal(t, " testing/testFile2", slowpage.MustElement("[aria-roledescription=file-uploading]").MustText(), "The testFile2 file has not started uploading") + slowpage.MustElementR("[aria-roledescription=files-uploading-count]", "1 file waiting to be uploaded...") + wait6() + slowpage.MustElementR("[aria-roledescription=file]", "testFile2").MustClick() + require.Contains(t, slowpage.MustElement("[aria-roledescription=preview-placeholder]").String(), "svg", "The modal did not open upon clicking the 130MB file") + slowpage.MustElement("#close-modal").MustClick() + } + + // Navigate out of nested folder and delete everything. + page.MustElement("#navigate-back").MustClick() + page.MustElement("button[aria-roledescription=dropdown]").MustClick() + page.MustElementR("button", "Delete").MustClick() + wait7 := page.MustWaitRequestIdle() + page.MustElementR("button", "Yes").MustClick() + wait7() + }) +} diff --git a/testsuite/ui/satellite/testdata/audio.mp3 b/testsuite/ui/satellite/testdata/audio.mp3 new file mode 100644 index 000000000..3c270d302 Binary files /dev/null and b/testsuite/ui/satellite/testdata/audio.mp3 differ diff --git a/testsuite/ui/satellite/testdata/img.png b/testsuite/ui/satellite/testdata/img.png new file mode 100644 index 000000000..71d0cdeae Binary files /dev/null and b/testsuite/ui/satellite/testdata/img.png differ diff --git a/testsuite/ui/satellite/testdata/img2.png b/testsuite/ui/satellite/testdata/img2.png new file mode 100644 index 000000000..71d0cdeae Binary files /dev/null and b/testsuite/ui/satellite/testdata/img2.png differ diff --git a/testsuite/ui/satellite/testdata/movie.mp4 b/testsuite/ui/satellite/testdata/movie.mp4 new file mode 100644 index 000000000..58eacd7a1 Binary files /dev/null and b/testsuite/ui/satellite/testdata/movie.mp4 differ diff --git a/testsuite/ui/satellite/testdata/test0bytes.txt b/testsuite/ui/satellite/testdata/test0bytes.txt new file mode 100644 index 000000000..e69de29bb diff --git a/testsuite/ui/satellite/util_test.go b/testsuite/ui/satellite/util_test.go index 536e33575..c21cc6c96 100644 --- a/testsuite/ui/satellite/util_test.go +++ b/testsuite/ui/satellite/util_test.go @@ -4,7 +4,16 @@ package satellite_test import ( + "os" + "testing" + "github.com/go-rod/rod" + "github.com/go-rod/rod/lib/input" + "github.com/stretchr/testify/require" + + "storj.io/common/memory" + "storj.io/common/testcontext" + "storj.io/storj/testsuite/ui/uitest" ) func waitVueTick(page *rod.Page) { @@ -17,3 +26,46 @@ func openPage(browser *rod.Browser, url string) *rod.Page { page.MustNavigate(url).MustWaitLoad() return page } + +func signUpWithUser(t *testing.T, planet *uitest.EdgePlanet, page *rod.Page) { + signupPageURL := planet.Satellites[0].ConsoleURL() + "/signup" + fullName := "John Doe" + emailAddress := "test@email.com" + password := "qazwsx123" + + // navigate to signup page + page.MustNavigate(signupPageURL) + + // first time User signup + page.MustElement("[aria-roledescription=name] input").MustInput(fullName) + page.MustElement("[aria-roledescription=email] input").MustInput(emailAddress) + page.MustElement("[aria-roledescription=password] input").MustInput(password) + page.MustElement("[aria-roledescription=retype-password] input").MustInput(password) + page.MustElement(".checkmark").MustClick() + page.Keyboard.MustPress(input.Enter) + confirmAccountEmailMessage := page.MustElement("[aria-roledescription=title]").MustText() + require.Contains(t, confirmAccountEmailMessage, "You're almost there!") +} + +func loginWithUser(t *testing.T, planet *uitest.EdgePlanet, page *rod.Page) { + loginPageURL := planet.Satellites[0].ConsoleURL() + "/login" + emailAddress := "test@email.com" + password := "qazwsx123" + + // navigate to login page + page.MustNavigate(loginPageURL) + + // login + page.MustElement("[aria-roledescription=email] input").MustInput(emailAddress) + page.MustElement("[aria-roledescription=password] input").MustInput(password) + page.Keyboard.MustPress(input.Enter) +} + +func generateEmptyFile(t *testing.T, ctx *testcontext.Context, name string, size memory.Size) string { + path := ctx.File(name) + f, err := os.Create(path) + require.NoError(t, err) + defer func() { require.NoError(t, f.Close()) }() + require.NoError(t, f.Truncate(size.Int64())) + return path +} diff --git a/testsuite/ui/uitest/browser.go b/testsuite/ui/uitest/browser.go index 4f6cdd429..6455c1fff 100644 --- a/testsuite/ui/uitest/browser.go +++ b/testsuite/ui/uitest/browser.go @@ -46,7 +46,7 @@ func Browser(t *testing.T, ctx *testcontext.Context, fn func(*rod.Browser)) { Logger(zapWriter{Logger: logLauncher}). Set("enable-logging"). Set("disable-gpu"). - Set("disable-web-security") // TODO: ensure we have proper CORS for testing + Set("disable-web-security") // TODO: ensure we have proper CORS for testing. if browserHost := os.Getenv("STORJ_TEST_BROWER_HOSTPORT"); browserHost != "" { host, port, err := net.SplitHostPort(browserHost) @@ -70,7 +70,7 @@ func Browser(t *testing.T, ctx *testcontext.Context, fn func(*rod.Browser)) { browser := rod.New(). Timeout(time.Minute). - Sleeper(func() utils.Sleeper { return timeoutSleeper(5*time.Second, 5) }). + Sleeper(MaxDuration(5 * time.Second)). ControlURL(url). Logger(utils.Log(func(msg ...interface{}) { logBrowser.Info(fmt.Sprintln(msg...)) @@ -106,27 +106,40 @@ func browserTimeoutDetector(duration time.Duration) context.CancelFunc { return cancel } -func timeoutSleeper(totalSleep time.Duration, maxTries int) utils.Sleeper { - singleSleep := totalSleep / time.Duration(maxTries) +// MaxDuration returns a sleeper constructor with the max duration. +func MaxDuration(max time.Duration) func() utils.Sleeper { + return func() utils.Sleeper { + singleSleep := 50 * time.Millisecond + totalSlept := time.Duration(0) + return func(ctx context.Context) error { + if totalSlept > max { + return errMaxSleepDuration(max) + } + if singleSleep > 500*time.Millisecond { + singleSleep = 500 * time.Millisecond + } - var slept int - return func(ctx context.Context) error { - slept++ - if slept > maxTries { - return &utils.ErrMaxSleepCount{Max: maxTries} + totalSlept += singleSleep + t := time.NewTimer(singleSleep) + defer t.Stop() + select { + case <-t.C: + case <-ctx.Done(): + } + + return nil } - - t := time.NewTimer(singleSleep) - defer t.Stop() - select { - case <-t.C: - case <-ctx.Done(): - } - - return nil } } +// errMaxSleepDuration is error for exceeding sleep duration. +type errMaxSleepDuration time.Duration + +// Error implements error interface. +func (e errMaxSleepDuration) Error() string { + return fmt.Sprintf("max sleep %v exceeded", time.Duration(e)) +} + func avoidStall(maxDuration time.Duration, fn func()) { done := make(chan struct{}) go func() { diff --git a/testsuite/ui/uitest/edge.go b/testsuite/ui/uitest/edge.go index 0045132ed..6b36d2a20 100644 --- a/testsuite/ui/uitest/edge.go +++ b/testsuite/ui/uitest/edge.go @@ -72,7 +72,7 @@ func Edge(t *testing.T, test EdgeTest) { config.Console.StaticDir = dir } config.Console.NewOnboarding = true - config.Console.NewObjectsFlow = true + config.Console.NewBrowser = true // TODO: this should be dynamically set from the auth service config.Console.GatewayCredentialsRequestURL = "http://" + authSvcAddr }, diff --git a/testsuite/ui/uitest/run.go b/testsuite/ui/uitest/run.go index 837eb16b3..bdf4e65cb 100644 --- a/testsuite/ui/uitest/run.go +++ b/testsuite/ui/uitest/run.go @@ -41,6 +41,7 @@ func Run(t *testing.T, test Test) { } config.Console.NewOnboarding = true config.Console.NewNavigation = true + config.Console.NewBrowser = true config.Console.CouponCodeBillingUIEnabled = true config.Console.NewObjectsFlow = true }, diff --git a/web/satellite/src/components/header/HeaderArea.vue b/web/satellite/src/components/header/HeaderArea.vue index 988c4b878..f0349090b 100644 --- a/web/satellite/src/components/header/HeaderArea.vue +++ b/web/satellite/src/components/header/HeaderArea.vue @@ -7,6 +7,7 @@