ci: run UI tests

We have implemented few UI tests using go-rod, but haven't been running
them regularly.

Change-Id: I6c89365f719882431842a2026b426860f1293b8b
This commit is contained in:
Egon Elbre 2021-09-22 12:20:03 +03:00
parent 8a21a8cbc5
commit 6ab2647adb
15 changed files with 233 additions and 143 deletions

View File

@ -94,6 +94,9 @@ pipeline {
sh 'npm ci --prefer-offline --no-audit'
sh 'npm run build'
}
sh 'cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" web/satellite/static/wasm/wasm_exec.js'
sh 'GOOS=js GOARCH=wasm go build -o web/satellite/static/wasm/access.wasm storj.io/storj/satellite/console/wasm'
}
}
stage('web/storagenode') {
@ -340,6 +343,39 @@ pipeline {
}
}
stage('UI') {
when {
anyOf {
branch 'main'
branch pattern: "release-.*", comparator: "REGEXP"
changeset "testsuite/**"
changeset "web/**"
changeset "satellite/console/**"
changeset "storagenode/console/**"
changeset "multinode/console/**"
}
}
environment {
STORJ_TEST_COCKROACH = 'omit'
STORJ_TEST_POSTGRES = 'postgres://postgres@localhost/testui?sslmode=disable'
STORJ_TEST_BROWSER = '/usr/bin/chromium'
STORJ_TEST_SATELLITE_WEB = "${pwd()}/web/satellite"
}
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'
}
}
post {
always {
sh script: 'cat .build/ui-tests.json | tparse -all -top -slow 100', returnStatus: true
archiveArtifacts artifacts: '.build/ui-tests.json'
junit '.build/ui-tests.xml'
}
}
}
stage('Post') {
parallel {
stage('Lint') {

View File

@ -1,78 +0,0 @@
pipeline {
agent {
docker {
label 'main'
image docker.build("storj-ci", "--pull git://github.com/storj/ci.git#main").id
args '-u root:root --cap-add SYS_PTRACE -v "/tmp/gomod":/go/pkg/mod -v "/tmp/npm":/npm --tmpfs "/tmp:exec,mode=777"'
}
}
options {
timeout(time: 40, unit: 'MINUTES')
}
environment {
NPM_CONFIG_CACHE = '/npm/cache'
GOTRACEBACK = 'all'
COCKROACH_MEMPROF_INTERVAL=0
}
stages {
stage('Build') {
steps {
checkout scm
sh 'mkdir -p .build'
sh 'go mod download'
sh 'service postgresql start'
dir(".build") {
sh 'cockroach start-single-node --insecure --store=type=mem,size=2GiB --listen-addr=localhost:26256 --http-addr=localhost:8086 --cache 512MiB --max-sql-memory 512MiB --background'
}
}
}
stage('UI') {
environment {
STORJ_TEST_COCKROACH = 'cockroach://root@localhost:26256/testui?sslmode=disable'
STORJ_TEST_POSTGRES = 'postgres://postgres@localhost/testui?sslmode=disable'
STORJ_TEST_BROWSER = '/usr/bin/chromium'
STORJ_TEST_SATELLITE_WEB = "${pwd()}/.build/satellite-web"
DISPLAY = ':99'
}
steps {
sh 'cockroach sql --insecure --host=localhost:26256 -e \'create database testui;\''
sh 'psql -U postgres -c \'create database testui;\''
sh 'cp -r ./web/satellite/ ${STORJ_TEST_SATELLITE_WEB}/'
// TODO: this is not quite correct
sh 'mkdir ${STORJ_TEST_SATELLITE_WEB}/wasm'
sh 'cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" ${STORJ_TEST_SATELLITE_WEB}/wasm/wasm_exec.js'
sh 'GOOS=js GOARCH=wasm go build -o ${STORJ_TEST_SATELLITE_WEB}/wasm/main.wasm storj.io/storj/satellite/console/wasm'
sh 'cd .build/satellite-web && npm install'
sh 'cd .build/satellite-web && npm run build'
sh 'Xvfb -ac :99 -screen 0 1280x1024x16 &'
sh 'cd testsuite && go test -vet=off -race -json ./ui/... 2>&1 | tee ../.build/ui-tests.json | xunit -out ../.build/ui-tests.xml'
}
post {
always {
sh script: 'cat .build/ui-tests.json | tparse -all -top -slow 100', returnStatus: true
archiveArtifacts artifacts: '.build/ui-tests.json'
junit '.build/ui-tests.xml'
}
}
}
}
post {
always {
sh "chmod -R 777 ." // ensure Jenkins agent can delete the working directory
deleteDir()
}
}
}

View File

@ -5,7 +5,7 @@ go 1.16
replace storj.io/storj => ../
require (
github.com/go-rod/rod v0.100.0
github.com/go-rod/rod v0.101.8
github.com/stretchr/testify v1.7.0
go.uber.org/zap v1.17.0
storj.io/common v0.0.0-20210928143209-230bee624465

View File

@ -121,8 +121,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-redis/redis/v8 v8.7.1 h1:8IYi6RO83fNcG5amcUUYTN/qH2h4OjZHlim3KWGFSsA=
github.com/go-redis/redis/v8 v8.7.1/go.mod h1:BRxHBWn3pO3CfjyX6vAoyeRmCquvxr6QG+2onGV2gYs=
github.com/go-rod/rod v0.100.0 h1:tEKIb5wS3pGUpW4oJPYDxOKmRXaZbd6S+YVjJ6BHBBY=
github.com/go-rod/rod v0.100.0/go.mod h1:h9igqSGReLmOWyHtdf0AtUd0mdkHFu3gFwBeV+stleM=
github.com/go-rod/rod v0.101.8 h1:oV0O97uwjkCVyAP0hD6K6bBE8FUMIjs0dtF7l6kEBsU=
github.com/go-rod/rod v0.101.8/go.mod h1:N/zlT53CfSpq74nb6rOR0K8UF0SPUPBmzBnArrms+mY=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
@ -487,8 +487,8 @@ github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEAB
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
github.com/ysmood/goob v0.3.0 h1:XZ51cZJ4W3WCoCiUktixzMIQF86W7G5VFL4QQ/Q2uS0=
github.com/ysmood/goob v0.3.0/go.mod h1:S3lq113Y91y1UBf1wj1pFOxeahvfKkCk6mTWTWbDdWs=
github.com/ysmood/got v0.12.0 h1:Ol4cpy6Xdq1KCjPlWSA+tvekrnt9cV6LIw+Jvx0dj4M=
github.com/ysmood/got v0.12.0/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
github.com/ysmood/got v0.15.1 h1:X5jAbMyBf5yeezuFMp9HaMGXZWMSqIQcUlAHI+kJmUs=
github.com/ysmood/got v0.15.1/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
github.com/ysmood/gotrace v0.2.2 h1:006KHGRThSRf8lwh4EyhNmuuq/l+Ygs+JqojkhEG1/E=
github.com/ysmood/gotrace v0.2.2/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM=
github.com/ysmood/gson v0.6.4 h1:Yb6tosv6bk59HqjZu2/7o4BFherpYEMkDkXmlhgryZ4=

View File

@ -1,15 +1,17 @@
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
package satellite
package satellite_test
import (
"testing"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/input"
"github.com/stretchr/testify/require"
"storj.io/common/sync2"
"storj.io/common/testcontext"
"storj.io/storj/private/testplanet"
"storj.io/storj/testsuite/ui/uitest"
@ -22,8 +24,7 @@ func TestOnboardingWizardCLIFlow(t *testing.T) {
emailAddress := "test@email.com"
password := "qazwsx123"
page := browser.MustPage(signupPageURL)
page.MustSetViewport(1350, 600, 1, false)
page := openPage(browser, signupPageURL)
// First time User signup
page.MustElement("[aria-roledescription=name] input").MustInput(fullName)
@ -32,6 +33,8 @@ func TestOnboardingWizardCLIFlow(t *testing.T) {
page.MustElement("[aria-roledescription=retype-password] input").MustInput(password)
page.MustElement(".checkmark").MustClick()
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
confirmAccountEmailMessage := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, confirmAccountEmailMessage, "You're almost there!")
@ -40,13 +43,20 @@ func TestOnboardingWizardCLIFlow(t *testing.T) {
page.MustElement("[aria-roledescription=email] input").MustInput(emailAddress)
page.MustElement("[aria-roledescription=password] input").MustInput(password)
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
// Testing onboarding workflow uplinkCLI method
// Welcome screen
page.MustElementX("(//span[text()=\"Continue in cli\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
// API key generated screen
// TODO: Using sleep here, because waiting for the next tick and element
// does not work properly. The loading of WASM seems to take a bunch of time
// throwing things off.
require.True(t, sync2.Sleep(ctx, time.Second))
apiKeyGeneratedTitle := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, apiKeyGeneratedTitle, "API Key Generated")
satelliteAddress := page.MustElement("[aria-roledescription=satellite-address]").MustText()
@ -54,12 +64,12 @@ func TestOnboardingWizardCLIFlow(t *testing.T) {
apiKey := page.MustElement("[aria-roledescription=api-key]").MustText()
require.NotEmpty(t, apiKey)
page.MustElementX("(//span[text()=\"< Back\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
welcomeTitle := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, welcomeTitle, "Welcome")
page.MustElementX("(//span[text()=\"Continue in cli\"])").MustClick()
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
// API key generated screen
cliInstallTitle := page.MustElement("[aria-roledescription=title]").MustText()
@ -84,13 +94,13 @@ func TestOnboardingWizardCLIFlow(t *testing.T) {
// Back and forth click test
page.MustElementX("(//span[text()=\"< Back\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
apiKeyGeneratedTitle1 := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, apiKeyGeneratedTitle1, "API Key Generated")
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
// CLI setup screen
cliSetupTitle := page.MustElement("[aria-roledescription=title]").MustText()
@ -109,13 +119,13 @@ func TestOnboardingWizardCLIFlow(t *testing.T) {
// Back and forth click test
page.MustElementX("(//span[text()=\"< Back\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
cliInstallTitle1 := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, cliInstallTitle1, "Install Uplink CLI")
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
// Create bucket screen
createBucketTitle := page.MustElement("[aria-roledescription=title]").MustText()
@ -134,13 +144,13 @@ func TestOnboardingWizardCLIFlow(t *testing.T) {
// Back and forth click test
page.MustElementX("(//span[text()=\"< Back\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
cliSetupTitle1 := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, cliSetupTitle1, "CLI Setup")
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
// Ready to upload screen
readyToUploadTitle := page.MustElement("[aria-roledescription=title]").MustText()
@ -159,13 +169,13 @@ func TestOnboardingWizardCLIFlow(t *testing.T) {
// Back and forth click test
page.MustElementX("(//span[text()=\"< Back\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
createBucketTitle1 := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, createBucketTitle1, "Create a bucket")
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
// List a bucket screen
listTitle := page.MustElement("[aria-roledescription=title]").MustText()
@ -184,13 +194,13 @@ func TestOnboardingWizardCLIFlow(t *testing.T) {
// Back and forth click test
page.MustElementX("(//span[text()=\"< Back\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
readyToUploadTitle1 := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, readyToUploadTitle1, "Ready to upload")
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
// Download screen
downloadTitle := page.MustElement("[aria-roledescription=title]").MustText()
@ -209,13 +219,13 @@ func TestOnboardingWizardCLIFlow(t *testing.T) {
// Back and forth click test
page.MustElementX("(//span[text()=\"< Back\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
listTitle1 := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, listTitle1, "Listing a bucket")
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
// Share link screen
shareLinkTitle := page.MustElement("[aria-roledescription=title]").MustText()
@ -234,19 +244,19 @@ func TestOnboardingWizardCLIFlow(t *testing.T) {
// Back and forth click test
page.MustElementX("(//span[text()=\"< Back\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
downloadTitle1 := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, downloadTitle1, "Download")
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
// Success screen
successTitle := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, successTitle, "Wonderful")
page.MustElementX("(//span[text()=\"Finish\"])").MustClick()
page.MustWaitNavigation()
waitVueTick(page)
dashboardTitle := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, dashboardTitle, "My First Project Dashboard")
page.MustNavigateBack()

View File

@ -1,7 +1,7 @@
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
package satellite
package satellite_test
import (
"testing"
@ -22,8 +22,7 @@ func TestOnboardingWizardBrowser(t *testing.T) {
emailAddress := "test@email.com"
password := "qazwsx123"
page := browser.MustPage(signupPageURL)
page.MustSetViewport(1350, 600, 1, false)
page := openPage(browser, signupPageURL)
// first time User signup
page.MustElement("[aria-roledescription=name] input").MustInput(fullName)
@ -32,20 +31,26 @@ func TestOnboardingWizardBrowser(t *testing.T) {
page.MustElement("[aria-roledescription=retype-password] input").MustInput(password)
page.MustElement(".checkmark").MustClick()
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
confirmAccountEmailMessage := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, confirmAccountEmailMessage, "You're almost there!")
// first time user log in
page.MustElement("[href=\"/login\"]").MustClick()
waitVueTick(page)
page.MustElement("[aria-roledescription=email] input").MustInput(emailAddress)
page.MustElement("[aria-roledescription=password] input").MustInput(password)
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
// testing onboarding workflow browser
page.MustElementX("(//span[text()=\"Continue in web\"])").MustClick()
waitVueTick(page)
objectBrowserWarning := page.MustElement("[aria-roledescription=sub-title]").MustText()
require.Contains(t, objectBrowserWarning, "The object browser uses server side encryption.")
page.MustElementX("(//span[text()=\"Continue\"])").MustClick()
waitVueTick(page)
encryptionPassphraseWarningTitle := page.MustElement("[aria-roledescription=warning-title]").MustText()
require.Contains(t, encryptionPassphraseWarningTitle, "The object browser uses server side encryption.")
@ -53,9 +58,11 @@ func TestOnboardingWizardBrowser(t *testing.T) {
customPassphraseLabel := customPassphrase.MustText()
require.Contains(t, customPassphraseLabel, "Enter Your Own Passphrase")
customPassphrase.MustClick()
waitVueTick(page)
page.MustElement("[aria-roledescription=passphrase] input").MustInput("password123")
page.MustElementX("(//span[text()=\"Next >\"])").MustClick()
waitVueTick(page)
// Buckets Page
bucketsTitle := page.MustElement("[aria-roledescription=title]").MustText()

View File

@ -1,7 +1,7 @@
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
package satellite
package satellite_test
import (
"testing"
@ -22,8 +22,7 @@ func TestRestartOnboardingWizard(t *testing.T) {
emailAddress := "test@email.com"
password := "qazwsx123"
page := browser.MustPage(signupPageURL)
page.MustSetViewport(1350, 600, 1, false)
page := openPage(browser, signupPageURL)
// First time User signup
page.MustElement("[aria-roledescription=name] input").MustInput(fullName)
@ -32,6 +31,8 @@ func TestRestartOnboardingWizard(t *testing.T) {
page.MustElement("[aria-roledescription=retype-password] input").MustInput(password)
page.MustElement(".checkmark").MustClick()
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
confirmAccountEmailMessage := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, confirmAccountEmailMessage, "You're almost there!")
@ -40,6 +41,7 @@ func TestRestartOnboardingWizard(t *testing.T) {
page.MustElement("[aria-roledescription=email] input").MustInput(emailAddress)
page.MustElement("[aria-roledescription=password] input").MustInput(password)
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
// Checking out skip of onboarding process
page.MustElement("[href=\"/project-dashboard\"]").MustClick()
@ -49,6 +51,8 @@ func TestRestartOnboardingWizard(t *testing.T) {
// Testing restart tour functionality
page.MustElement("[aria-roledescription=restart-onb-icon]").MustHover()
page.MustElementX("(//span[text()=\"Start tour\"])").MustClick()
waitVueTick(page)
welcomeTitle := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, welcomeTitle, "Welcome")
})

View File

@ -1,7 +1,7 @@
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
package satellite
package satellite_test
import (
"testing"
@ -22,8 +22,7 @@ func TestOnboardingWelcomeScreenEncryption(t *testing.T) {
emailAddress := "test@email.com"
password := "qazwsx123"
page := browser.MustPage(signupPageURL)
page.MustSetViewport(1350, 600, 1, false)
page := openPage(browser, signupPageURL)
// First time User signup
page.MustElement("[aria-roledescription=name] input").MustInput(fullName)
@ -32,6 +31,8 @@ func TestOnboardingWelcomeScreenEncryption(t *testing.T) {
page.MustElement("[aria-roledescription=retype-password] input").MustInput(password)
page.MustElement(".checkmark").MustClick()
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
confirmAccountEmailMessage := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, confirmAccountEmailMessage, "You're almost there!")
@ -40,6 +41,7 @@ func TestOnboardingWelcomeScreenEncryption(t *testing.T) {
page.MustElement("[aria-roledescription=email] input").MustInput(emailAddress)
page.MustElement("[aria-roledescription=password] input").MustInput(password)
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
// Welcome screen encryption test
welcomeTitle := page.MustElement("[aria-roledescription=title]").MustText()

View File

@ -1,7 +1,7 @@
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
package satellite
package satellite_test
import (
"testing"
@ -24,8 +24,7 @@ func TestBusinessUserCanSignUp(t *testing.T) {
companyName := "company"
positionTitle := "tester"
page := browser.MustPage(signupPageURL)
page.MustSetViewport(1350, 600, 1, false)
page := openPage(browser, signupPageURL)
// First time User signup
page.MustElement("[aria-roledescription=professional-label]").MustClick()
@ -37,6 +36,8 @@ func TestBusinessUserCanSignUp(t *testing.T) {
page.MustElement("[aria-roledescription=retype-password] input").MustInput(password)
page.MustElementX("(//*[@class=\"checkmark\"])[2]").MustClick()
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
confirmAccountEmailMessage := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, confirmAccountEmailMessage, "You're almost there!")
})

View File

@ -1,7 +1,7 @@
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
package satellite
package satellite_test
import (
"testing"
@ -21,8 +21,8 @@ func TestSignUpContent(t *testing.T) {
fullName := "John Doe"
invalidEmailAddress := "test@email"
password := "qazwsx123"
page := browser.MustPage(signupPageURL)
page.MustSetViewport(1350, 600, 1, false)
page := openPage(browser, signupPageURL)
// Satellites dropdown
page.MustElement("[aria-roledescription=satellites-dropdown]").MustClick()
@ -33,6 +33,7 @@ func TestSignUpContent(t *testing.T) {
apSatLink := page.MustElement("[href=\"https://ap1.storj.io/signup\"]").MustText()
require.Contains(t, apSatLink, "AP1")
page.MustElement("[aria-roledescription=satellites-dropdown]").MustClick()
waitVueTick(page)
// User signup with invalid email
page.MustElement("[aria-roledescription=name] input").MustInput(fullName)
@ -41,6 +42,8 @@ func TestSignUpContent(t *testing.T) {
page.MustElement("[aria-roledescription=retype-password] input").MustInput(password)
page.MustElement(".checkmark").MustClick()
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
invalidEmailMessage := page.MustElement("[aria-roledescription=email] [aria-roledescription=error-text]").MustText()
require.Contains(t, invalidEmailMessage, "Invalid Email")
@ -49,6 +52,8 @@ func TestSignUpContent(t *testing.T) {
page.MustElement("[aria-roledescription=password] input").MustSelectAllText().MustInput("")
page.MustElement("[aria-roledescription=retype-password] input").MustSelectAllText().MustInput("")
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
invalidEmailMessage1 := page.MustElement("[aria-roledescription=email] [aria-roledescription=error-text]").MustText()
require.Contains(t, invalidEmailMessage1, "Invalid Email")
invalidPasswordMessage := page.MustElement("[aria-roledescription=password] [aria-roledescription=error-text]").MustText()

View File

@ -1,7 +1,7 @@
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
package satellite
package satellite_test
import (
"testing"
@ -21,8 +21,8 @@ func TestPersonalUserCanSignUp(t *testing.T) {
fullName := "John Doe"
emailAddress := "test@email.com"
password := "qazwsx123"
page := browser.MustPage(signupPageURL)
page.MustSetViewport(1350, 600, 1, false)
page := openPage(browser, signupPageURL)
// First time User signup
page.MustElement("[aria-roledescription=name] input").MustInput(fullName)
@ -31,6 +31,8 @@ func TestPersonalUserCanSignUp(t *testing.T) {
page.MustElement("[aria-roledescription=retype-password] input").MustInput(password)
page.MustElement(".checkmark").MustClick()
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
confirmAccountEmailMessage := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, confirmAccountEmailMessage, "You're almost there!")
})

View File

@ -5,7 +5,6 @@ package satellite_test
import (
"testing"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/input"
@ -21,12 +20,12 @@ func TestLoginToAccount(t *testing.T) {
loginPageURL := planet.Satellites[0].ConsoleURL() + "/login"
user := planet.Uplinks[0].User[planet.Satellites[0].ID()]
page := browser.Timeout(10 * time.Second).MustPage(loginPageURL)
page.MustSetViewport(1350, 600, 1, false)
page := openPage(browser, loginPageURL)
page.MustElement("[aria-roledescription=email] input").MustInput(user.Email)
page.MustElement("[aria-roledescription=password] input").MustInput(user.Password)
page.Keyboard.MustPress(input.Enter)
waitVueTick(page)
dashboardTitle := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, dashboardTitle, "Dashboard")

View File

@ -0,0 +1,19 @@
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
package satellite_test
import (
"github.com/go-rod/rod"
)
func waitVueTick(page *rod.Page) {
page.MustEval("VueNextTick()")
}
func openPage(browser *rod.Browser, url string) *rod.Page {
page := browser.MustPage()
page.MustSetViewport(1350, 600, 1, false)
page.MustNavigate(url).MustWaitLoad()
return page
}

View File

@ -4,13 +4,17 @@
package uitest
import (
"context"
"fmt"
"net"
"os"
"testing"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/defaults"
"github.com/go-rod/rod/lib/launcher"
"github.com/go-rod/rod/lib/launcher/flags"
"github.com/go-rod/rod/lib/utils"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
@ -21,6 +25,11 @@ import (
"storj.io/storj/satellite"
)
// Our testing suite heavily uses randomly selected ports, which may collide
// with the launcher lock port. We'll disable the lock port entirely for
// the time being.
func init() { defaults.LockPort = 0 }
// Test defines common services for uitests.
type Test func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet, browser *rod.Browser)
@ -35,39 +44,50 @@ func (log zapWriter) Write(data []byte) (int, error) {
// Run starts a new UI test.
func Run(t *testing.T, test Test) {
if os.Getenv("STORJ_TEST_SATELLITE_WEB") == "" {
t.Skip("Enable UI tests by setting STORJ_TEST_SATELLITE_WEB to built npm")
}
if os.Getenv("STORJ_TEST_SATELLITE_WEB") == "omit" {
return
}
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 4, UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
config.Console.StaticDir = os.Getenv("STORJ_TEST_SATELLITE_WEB")
if dir := os.Getenv("STORJ_TEST_SATELLITE_WEB"); dir != "" {
config.Console.StaticDir = dir
}
config.Console.NewOnboarding = true
},
},
NonParallel: true,
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
showBrowser := os.Getenv("STORJ_TEST_SHOW_BROWSER") != ""
slowBrowser := os.Getenv("STORJ_TEST_SHOW_BROWSER") == "slow"
logLauncher := zaptest.NewLogger(t).Named("launcher")
browserLoaded := browserTimeoutDetector(10 * time.Second)
defer browserLoaded()
launch := launcher.New().
Headless(!showBrowser).
Leakless(false).
Devtools(false).
NoSandbox(true).
UserDataDir(ctx.Dir("browser")).
Logger(zapWriter{Logger: logLauncher})
Logger(zapWriter{Logger: logLauncher}).
Set("enable-logging").
Set("disable-gpu")
if browserHost := os.Getenv("STORJ_TEST_BROWER_HOSTPORT"); browserHost != "" {
host, port, err := net.SplitHostPort(browserHost)
require.NoError(t, err)
launch = launch.Set("remote-debugging-address", host).Set(flags.RemoteDebuggingPort, port)
}
if browserBin := os.Getenv("STORJ_TEST_BROWSER"); browserBin != "" {
launch = launch.Bin(browserBin)
}
defer launch.Cleanup()
defer func() {
launch.Kill()
avoidStall(3*time.Second, launch.Cleanup)
}()
url, err := launch.Launch()
require.NoError(t, err)
@ -76,17 +96,76 @@ func Run(t *testing.T, test Test) {
browser := rod.New().
Timeout(time.Minute).
Sleeper(func() utils.Sleeper { return timeoutSleeper(5*time.Second, 5) }).
ControlURL(url).
SlowMotion(300 * time.Millisecond).
Logger(utils.Log(func(msg ...interface{}) {
logBrowser.Info(fmt.Sprintln(msg...))
})).
Context(ctx).
WithPanic(func(v interface{}) { require.Fail(t, "check failed", v) })
if slowBrowser {
browser = browser.SlowMotion(300 * time.Millisecond).Trace(true)
}
defer ctx.Check(browser.Close)
require.NoError(t, browser.Connect())
browserLoaded()
test(t, ctx, planet, browser)
})
}
func browserTimeoutDetector(duration time.Duration) context.CancelFunc {
ctx, cancel := context.WithCancel(context.Background())
go func() {
t := time.NewTimer(duration)
defer t.Stop()
select {
case <-t.C:
panic("timeout for starting browser exceeded")
case <-ctx.Done():
return
}
}()
return cancel
}
func timeoutSleeper(totalSleep time.Duration, maxTries int) utils.Sleeper {
singleSleep := totalSleep / time.Duration(maxTries)
var slept int
return func(ctx context.Context) error {
slept++
if slept > maxTries {
return &utils.ErrMaxSleepCount{Max: maxTries}
}
t := time.NewTimer(singleSleep)
defer t.Stop()
select {
case <-t.C:
case <-ctx.Done():
}
return nil
}
}
func avoidStall(maxDuration time.Duration, fn func()) {
done := make(chan struct{})
go func() {
fn()
close(done)
}()
timeout := time.NewTicker(maxDuration)
defer timeout.Stop()
select {
case <-done:
case <-timeout.C:
fmt.Printf("go-rod did not shutdown within %v\n", maxDuration)
}
}

View File

@ -11,6 +11,10 @@ import App from './App.vue';
import { router } from './router';
import { store } from './store';
window['VueNextTick'] = function(callback) {
return Vue.nextTick(callback);
};
Vue.config.devtools = true;
Vue.config.performance = true;
Vue.config.productionTip = false;