How to use NewValidationResult method of validation Package

Best Gauge code snippet using validation.NewValidationResult

serializers.go

Source:serializers.go Github

copy

Full Screen

...39/*40Validate validates serializer41*/42func (u *UserProfileSerializer) Validate(cfg Config) (result ValidationResult) {43	result = NewValidationResult()44	u.FirstName = strings.TrimSpace(u.FirstName)45	u.LastName = strings.TrimSpace(u.LastName)46	u.Email = strings.TrimSpace(u.Email)47	if u.Email != "" && !govalidator.IsEmail(u.Email) {48		result.AddFieldError("email", errors.New("Invalid email"), "invalid_email")49	}50	return51}52/*53Serializer to create new user54*/55type UserAddSerializer struct {56	Username    string `json:"username"`57	FirstName   string `json:"first_name"`58	LastName    string `json:"last_name"`59	Email       string `json:"email"`60	Password    string `json:"password"`61	Password2   string `json:"password2"`62	IsActive    bool   `json:"is_active"`63	IsAdmin     bool   `json:"is_admin"`64	CanList     bool   `json:"can_list"`65	CanDownload bool   `json:"can_download"`66	CanCreate   bool   `json:"can_create"`67	CanUpdate   bool   `json:"can_update"`68}69/*70Validate validates information about new user71@TODO: add ValidateUsername and ValidateEmail72*/73func (u *UserAddSerializer) Validate(cfg Config) (result ValidationResult) {74	result = NewValidationResult()75	u.Username = strings.TrimSpace(u.Username)76	u.FirstName = strings.TrimSpace(u.FirstName)77	u.LastName = strings.TrimSpace(u.LastName)78	u.Email = strings.TrimSpace(u.Email)79	u.Password = strings.TrimSpace(u.Password)80	u.Password2 = strings.TrimSpace(u.Password2)81	// validate username82	if ValidateUsername("username", &(u.Username), result) {83		user := User{}84		if !cfg.DB().First(&user, "username = ?", u.Username).RecordNotFound() {85			result.AddFieldError("username", ErrUsernameAlreadyExists)86		}87	}88	// validate email89	if u.Email != "" {90		if !govalidator.IsEmail(u.Email) {91			result.AddFieldError("email", ErrInvalidEmail)92		} else {93			user := User{}94			if !cfg.DB().First(&user, "email = ?", u.Email).RecordNotFound() {95				result.AddFieldError("email", ErrEmailAlreadyExists)96			}97		}98	}99	// validate passwords100	ValidatePassword("password", &(u.Password), result)101	ValidatePassword("password2", &(u.Password2), result)102	if !result.HasFieldError("password") && !result.HasFieldError("password2") {103		if u.Password != u.Password2 {104			result.AddFieldError("password2", ErrPasswordsMustMatch)105		}106	}107	return108}109/*110return user initialized with serializer values111*/112func (u *UserAddSerializer) GetUser(cfg Config) (user User) {113	user = User{114		Username:    u.Username,115		FirstName:   u.FirstName,116		LastName:    u.LastName,117		Email:       u.Email,118		IsActive:    u.IsActive,119		IsAdmin:     u.IsAdmin,120		CanCreate:   u.CanCreate,121		CanList:     u.CanList,122		CanDownload: u.CanDownload,123		CanUpdate:   u.CanUpdate,124	}125	// set password126	cfg.Manager().User().SetPassword(&user, u.Password)127	return128}129/*130Serializer to update existing user131*/132type UserUpdateSerializer struct {133	ID          uint   `json:"-"`134	Username    string `json:"username"`135	FirstName   string `json:"first_name"`136	LastName    string `json:"last_name"`137	Email       string `json:"email"`138	Password    string `json:"password"`139	Password2   string `json:"password2"`140	IsActive    bool   `json:"is_active"`141	IsAdmin     bool   `json:"is_admin"`142	CanList     bool   `json:"can_list"`143	CanDownload bool   `json:"can_download"`144	CanCreate   bool   `json:"can_create"`145	CanUpdate   bool   `json:"can_update"`146	// mark that user is changing password147	passwordChange bool148}149/*150Validate validates data in serializer151*/152func (u *UserUpdateSerializer) Validate(cfg Config) (result ValidationResult) {153	result = NewValidationResult()154	u.FirstName = strings.TrimSpace(u.FirstName)155	u.LastName = strings.TrimSpace(u.LastName)156	u.Email = strings.TrimSpace(u.Email)157	u.Password = strings.TrimSpace(u.Password)158	u.Password2 = strings.TrimSpace(u.Password2)159	// validate username160	if ValidateUsername("username", &(u.Username), result) {161		count := 0162		cfg.DB().Model(User{}).Where("id != ? AND username = ?", u.ID, u.Username).Count(&count)163		if count > 0 {164			result.AddFieldError("username", ErrUsernameAlreadyExists)165		}166	}167	// validate email168	if u.Email != "" {169		if !govalidator.IsEmail(u.Email) {170			result.AddFieldError("email", ErrInvalidEmail)171		} else {172			user := User{}173			if !cfg.DB().First(&user, "email = ? AND id != ?", u.Email, u.ID).RecordNotFound() {174				result.AddFieldError("email", ErrEmailAlreadyExists)175			}176		}177	}178	// if any password has been given perform validation179	if u.Password != "" || u.Password2 != "" {180		// mark that serializer changes password181		u.passwordChange = true182		ValidatePassword("password", &(u.Password), result)183		ValidatePassword("password2", &(u.Password2), result)184		if !result.HasFieldError("password") && !result.HasFieldError("password2") {185			if u.Password != u.Password2 {186				result.AddFieldError("password2", ErrPasswordsMustMatch)187			}188		}189	}190	return191}192/*193UpdateUser updates user with serializer data194*/195func (u *UserUpdateSerializer) UpdateUser(cfg Config, user *User) {196	user.Username = u.Username197	user.FirstName = u.FirstName198	user.LastName = u.LastName199	user.Email = u.Email200	if u.passwordChange {201		cfg.Manager().User().SetPassword(user, u.Password)202	}203	user.IsActive = u.IsActive204	user.IsAdmin = u.IsAdmin205	user.CanList = u.CanList206	user.CanDownload = u.CanDownload207	user.CanCreate = u.CanCreate208	user.CanUpdate = u.CanUpdate209}210/*211LicenseUpdateSerializer handles license update212*/213type LicenseUpdateSerializer struct {214	ID       uint   `json:"-"`215	Approved bool   `json:"approved"`216	Name     string `json:"name"`217	Content  string `json:"content"`218}219/*220Validate runs validation on serializer fields221*/222func (l *LicenseUpdateSerializer) Validate(cfg Config, ID int) (result ValidationResult) {223	result = NewValidationResult()224	l.ID = uint(ID)225	l.Name = strings.TrimSpace(l.Name)226	l.Content = strings.TrimSpace(l.Content)227	return228}229/*230Update license with data form serializer231*/232func (l *LicenseUpdateSerializer) UpdateLicense(license *License) {233	license.Name = l.Name234	license.Content = l.Content235	license.Approved = l.Approved236}237/*238Serializer to change password for currently logged user239*/240type UserChangePasswordSerializer struct {241	Current   string `json:"current"`242	Password  string `json:"password"`243	Password2 string `json:"password2"`244	User      User   `json:"-"`245}246/*247Validate validates serializer data248*/249func (u *UserChangePasswordSerializer) Validate(cfg Config) (result ValidationResult) {250	result = NewValidationResult()251	// validate current password252	if !cfg.Manager().User().VerifyPassword(u.User, u.Current) {253		result.AddFieldError("current", ErrLoginPassword)254		return255	}256	ValidatePassword("password", &(u.Password), result)257	ValidatePassword("password2", &(u.Password2), result)258	if !result.HasFieldError("password") && !result.HasFieldError("password2") {259		if u.Password != u.Password2 {260			result.AddFieldError("password2", ErrPasswordsMustMatch)261		}262	}263	return264}...

Full Screen

Full Screen

validationresult_test.go

Source:validationresult_test.go Github

copy

Full Screen

...30	if err != nil {31		t.Error(err)32		return33	}34	result, err := dpn.NewValidationResult(bagPath, nil)35	if err != nil {36		t.Error(err)37		return38	}39	defer cleanup(result)40	result.ValidateBag()41	if !result.IsValid() {42		for _, message := range result.ErrorMessages {43			t.Errorf(message)44		}45		t.Errorf("Bag should be valid.")46	}47}48func TestValidate_BagMissingDataFile(t *testing.T) {49	bagPath, err := getBagPath(BAG_MISSING_DATA_FILE)50	if err != nil {51		t.Error(err)52		return53	}54	result, err := dpn.NewValidationResult(bagPath, nil)55	if err != nil {56		t.Error(err)57		return58	}59	defer cleanup(result)60	result.ValidateBag()61	if result.IsValid() {62		t.Errorf("Bag should not be valid.")63	}64	if len(result.ErrorMessages) != 3 {65		t.Errorf("Bag should have 3 error messages, found %d", len(result.ErrorMessages))66		printErrors(result.ErrorMessages)67		return68	}69	if result.ErrorMessages[0] != "Required tag 'Interpretive-Object-ID' is missing from dpn-tags/dpn-info.txt" {70		t.Errorf("ValidationResult should have noted missing Interpretive-Object-ID")71	}72	if !strings.Contains(result.ErrorMessages[1], "checksum") {73		t.Errorf("ValidationResult should have noted bad checksum")74	}75	if !strings.Contains(result.ErrorMessages[2], "no such file") {76		t.Errorf("ValidationResult should have noted missing file")77	}78}79func TestValidate_BagMissingManifest256(t *testing.T) {80	bagPath, err := getBagPath(BAG_MISSING_MANIFEST256)81	if err != nil {82		t.Error(err)83		return84	}85	result, err := dpn.NewValidationResult(bagPath, nil)86	if err != nil {87		t.Error(err)88		return89	}90	defer cleanup(result)91	result.ValidateBag()92	if result.IsValid() {93		t.Errorf("Bag should not be valid.")94	}95	if len(result.ErrorMessages) != 1 {96		t.Errorf("Bag should have exactly 1 error message")97		return98	}99	if !strings.Contains(result.ErrorMessages[0],100		"Manifest file 'manifest-sha256.txt' is missing.") {101		t.Errorf("ValidationResult should have noted missing manifest-sha256.txt")102	}103}104func TestValidate_BagMissingTags(t *testing.T) {105	bagPath, err := getBagPath(BAG_MISSING_TAGS)106	if err != nil {107		t.Error(err)108		return109	}110	result, err := dpn.NewValidationResult(bagPath, nil)111	if err != nil {112		t.Error(err)113		return114	}115	defer cleanup(result)116	result.ValidateBag()117	if result.IsValid() {118		t.Errorf("Bag should not be valid.")119	}120	if len(result.ErrorMessages) != 3 {121		t.Errorf("Bag should have 3 error messages, found %d", len(result.ErrorMessages))122		printErrors(result.ErrorMessages)123		return124	}125	if !strings.Contains(result.ErrorMessages[0], "'DPN-Object-ID' is missing") {126		t.Errorf("ValidationResult should have noted missing DPN-Object-ID tag")127	}128	if !strings.Contains(result.ErrorMessages[1], "'Version-Number' is missing") {129		t.Errorf("ValidationResult should have noted missing Version-Number tag")130	}131	if result.ErrorMessages[2] != "Required tag 'Interpretive-Object-ID' is missing from dpn-tags/dpn-info.txt" {132		t.Errorf("ValidationResult should have noted missing Interpretive-Object-ID")133	}134}135func TestValidate_BagMissingTagManifest(t *testing.T) {136	bagPath, err := getBagPath(BAG_MISSING_TAG_MANIFEST)137	if err != nil {138		t.Error(err)139		return140	}141	result, err := dpn.NewValidationResult(bagPath, nil)142	if err != nil {143		t.Error(err)144		return145	}146	defer cleanup(result)147	result.ValidateBag()148	if result.IsValid() {149		t.Errorf("Bag should not be valid.")150	}151	if len(result.ErrorMessages) != 1 {152		t.Errorf("Bag should have exactly 1 error message")153		return154	}155	if !strings.Contains(result.ErrorMessages[0],156		"'tagmanifest-sha256.txt' is missing") {157		t.Errorf("ValidationResult should have noted missing tagmanifest-sha256.txt")158	}159}160func TestValidate_BagWithBadDPNTags(t *testing.T) {161	bagPath, err := getBagPath(BAG_BAD_DPN_TAGS)162	if err != nil {163		t.Error(err)164		return165	}166	result, err := dpn.NewValidationResult(bagPath, nil)167	if err != nil {168		t.Error(err)169		return170	}171	defer cleanup(result)172	result.ValidateBag()173	if result.IsValid() {174		t.Errorf("Bag should not be valid.")175	}176	if len(result.ErrorMessages) != 7 {177		t.Errorf("Bag should have 7 error messages, found %d", len(result.ErrorMessages))178		printErrors(result.ErrorMessages)179		return180	}181	if result.ErrorMessages[0] != "Required tag 'Interpretive-Object-ID' is missing from dpn-tags/dpn-info.txt" {182		t.Errorf("ValidationResult should have noted missing Interpretive-Object-ID")183	}184	if result.ErrorMessages[1] != "DPN tag DPN-Object-ID must match bag name." {185		t.Errorf("ValidationResult should have noted DPN tag DPN-Object-ID must match bag name.")186	}187	if result.ErrorMessages[2] != "DPN tag Local-ID cannot be empty." {188		t.Errorf("ValidationResult should have noted DPN tag Local-ID cannot be empty.")189	}190	if result.ErrorMessages[3] != "DPN tag Ingest-Node-Name cannot be empty." {191		t.Errorf("ValidationResult should have noted DPN tag Ingest-Node-Name cannot be empty.")192	}193	if result.ErrorMessages[4] != "DPN tag Version-Number must be an integer." {194		t.Errorf("ValidationResult should have noted DPN tag Version-Number must be an integer.")195	}196	if result.ErrorMessages[5] != "DPN tag First-Version-Object-ID must be a valid Version 4 UUID." {197		t.Errorf("ValidationResult should have noted DPN tag First-Version-Object-ID must be a valid Version 4 UUID.")198	}199	if result.ErrorMessages[6] != "DPN tag Bag-Type must be data, rights, or interpretive." {200		t.Errorf("ValidationResult should have noted DPN tag Bag-Type must be data, rights, or interpretive.")201	}202}203func TestValidate_Digest(t *testing.T) {204	bagPath, err := getBagPath(GOOD_BAG)205	if err != nil {206		t.Error(err)207		return208	}209	result, err := dpn.NewValidationResult(bagPath, nil)210	if err != nil {211		t.Error(err)212		return213	}214	defer cleanup(result)215	// Calling this unpacks the bag216	result.ValidateBag()217	result.CalculateTagManifestDigest("")218	expected := "204db9e51fb39acbd965d14e51149c443a1febeab225a1ca3d196b12b7b021bd"219	if result.TagManifestChecksum != expected {220		t.Errorf("Got tag manifest checksum '%s', expected '%s'",221			result.TagManifestChecksum, expected)222	}223	result.CalculateTagManifestDigest("GeorgeWBush")...

Full Screen

Full Screen

validator.go

Source:validator.go Github

copy

Full Screen

1package runtime2import (3	"fmt"4	"log"5	"strings"6	"github.com/commander-cli/commander/v2/pkg/matcher"7)8// ValidationResult will be returned after the validation was executed9type ValidationResult struct {10	Success bool11	Diff    string12}13func newValidationResult(m matcher.MatcherResult) ValidationResult {14	return ValidationResult{15		Success: m.Success,16		Diff:    m.Diff,17	}18}19// Validate validates the test results with the expected values20// The test should hold the result and expected to validate the result21func Validate(test TestCase) TestResult {22	equalMatcher := matcher.NewMatcher(matcher.Equal)23	log.Println("title: '"+test.Title+"'", " Stdout-Expected: ", test.Expected.Stdout)24	matcherResult := validateExpectedOut(test.Result.Stdout, test.Expected.Stdout)25	log.Println("title: '"+test.Title+"'", " Stdout-Result: ", matcherResult.Success)26	if !matcherResult.Success {27		return TestResult{28			ValidationResult: newValidationResult(matcherResult),29			TestCase:         test,30			FailedProperty:   Stdout,31		}32	}33	log.Println("title: '"+test.Title+"'", " Stderr-Expected: ", test.Expected.Stderr)34	matcherResult = validateExpectedOut(test.Result.Stderr, test.Expected.Stderr)35	log.Println("title: '"+test.Title+"'", " Stderr-Result: ", matcherResult.Success)36	if !matcherResult.Success {37		return TestResult{38			ValidationResult: newValidationResult(matcherResult),39			TestCase:         test,40			FailedProperty:   Stderr,41		}42	}43	log.Println("title: '"+test.Title+"'", " Exit-Expected: ", test.Expected.ExitCode)44	matcherResult = equalMatcher.Match(test.Result.ExitCode, test.Expected.ExitCode)45	log.Println("title: '"+test.Title+"'", " Exit-Result: ", matcherResult.Success)46	if !matcherResult.Success {47		return TestResult{48			ValidationResult: newValidationResult(matcherResult),49			TestCase:         test,50			FailedProperty:   ExitCode,51		}52	}53	return TestResult{54		ValidationResult: newValidationResult(matcherResult),55		TestCase:         test,56	}57}58func validateExpectedOut(got string, expected ExpectedOut) matcher.MatcherResult {59	var m matcher.Matcher60	var result matcher.MatcherResult61	result.Success = true62	if expected.Exactly != "" {63		m = matcher.NewMatcher(matcher.Text)64		if result = m.Match(got, expected.Exactly); !result.Success {65			return result66		}67	}68	m = matcher.NewMatcher(matcher.Contains)69	for _, c := range expected.Contains {70		if result = m.Match(got, c); !result.Success {71			return result72		}73	}74	if expected.LineCount != 0 {75		result = validateExpectedLineCount(got, expected)76		if !result.Success {77			return result78		}79	}80	if len(expected.Lines) > 0 {81		result = validateExpectedLines(got, expected)82		if !result.Success {83			return result84		}85	}86	m = matcher.NewMatcher(matcher.NotContains)87	for _, c := range expected.NotContains {88		if result = m.Match(got, c); !result.Success {89			return result90		}91	}92	m = matcher.NewMatcher(matcher.JSON)93	for i, v := range expected.JSON {94		if result = m.Match(got, map[string]string{i: v}); !result.Success {95			return result96		}97	}98	m = matcher.NewMatcher(matcher.XML)99	for i, v := range expected.XML {100		if result = m.Match(got, map[string]string{i: v}); !result.Success {101			return result102		}103	}104	if expected.File != "" {105		m = matcher.NewMatcher(matcher.File)106		if result = m.Match(got, expected.File); !result.Success {107			return result108		}109	}110	return result111}112func validateExpectedLineCount(got string, expected ExpectedOut) matcher.MatcherResult {113	m := matcher.NewMatcher(matcher.Equal)114	count := strings.Count(got, getLineBreak()) + 1115	if got == "" {116		count = 0117	}118	return m.Match(count, expected.LineCount)119}120func validateExpectedLines(got string, expected ExpectedOut) matcher.MatcherResult {121	m := matcher.NewMatcher(matcher.Equal)122	actualLines := strings.Split(got, getLineBreak())123	result := matcher.MatcherResult{Success: true}124	for key, expectedLine := range expected.Lines {125		// line number 0 or below 0126		if key <= 0 {127			panic(fmt.Sprintf("Invalid line number given %d", key))128		}129		// line number exceeds result set130		if key > len(actualLines) {131			return matcher.MatcherResult{132				Success: false,133				Diff: fmt.Sprintf(134					"Line number %d does not exists in result: \n\n%s",135					key,136					strings.Join(actualLines, "\n"),137				),138			}139		}140		if result = m.Match(actualLines[key-1], expectedLine); !result.Success {141			return result142		}143	}144	return result145}146func getLineBreak() string {147	return "\n"148}...

Full Screen

Full Screen

NewValidationResult

Using AI Code Generation

copy

Full Screen

1import (2func main() {3    validate := validator.New()4    result := validators.NewValidationResult()5    translator := en.New()6    universalTranslator := ut.New(translator, translator)7    enTranslator, _ := universalTranslator.GetTranslator("en")8    _ = en_translations.RegisterDefaultTranslations(validate, enTranslator)9    _ = validate.RegisterValidation("result", result.Result)10    type User struct {11    }12    user := User{Name: "test"}13    err := validate.Struct(user)14    if err != nil {15        validationError := err.(validator.ValidationErrors)16        for _, err := range validationError {17            if err.Tag() == "result" {18                fmt.Println(err.Translate(enTranslator))19            }20        }21    }22}

Full Screen

Full Screen

NewValidationResult

Using AI Code Generation

copy

Full Screen

1import (2func main() {3	err := validation.NewValidationResult()4	fmt.Println(err)5}6import (7func main() {8	err := validation.NewValidationResult()9	fmt.Println(err)10}11import "fmt"12func NewValidationResult() error {13	return fmt.Errorf("Validation Failed")14}15        /usr/local/go/src/validation (from $GOROOT)16        /home/rajesh/go/src/validation (from $GOPATH)17import (18func main() {19    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {20        fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))21    })22    http.ListenAndServe(":8080", nil)23}24import (25func main() {26    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {27        fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))28    })29    http.ListenAndServe(":8080", nil)30}

Full Screen

Full Screen

NewValidationResult

Using AI Code Generation

copy

Full Screen

1import (2func main() {3	result = validation.NewValidationResult()4	fmt.Println(result)5}6type ValidationResult struct {7}8func NewValidationResult() ValidationResult {9	return ValidationResult{Errors: make(map[string]string)}10}11import (12func main() {13    router := httprouter.New()14    router.GET("/hello/:name", hello)15    http.ListenAndServe(":8080", router)16}17func hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {18    fmt.Fprintf(w, "Hello, %s!", ps.ByName("name"))19}20./main.go:22: cannot use hello (type func(http.ResponseWriter, *http.Request, httprouter.Params)) as type httprouter.Handle in argument to router.GET21    /usr/lib/go/src/pkg/net/http (from $GOROOT)22    /home/andrew/Go/src/pkg/net/http (from $GOPATH)23    /usr/lib/go/src/pkg/math/rand (from $GOROOT)24    /home/andrew/Go/src/pkg/math/rand (from $GOPATH)

Full Screen

Full Screen

NewValidationResult

Using AI Code Generation

copy

Full Screen

1import (2func main() {3	v := validation.Validation{}4	vr := v.NewValidationResult("required", "")5	fmt.Println(vr)6}7import (8type ValidationResult struct {9	Value interface{}10}11type Validation struct {12}13func (v *Validation) NewValidationResult(name string, value interface{}) *ValidationResult {14	vr := &ValidationResult{}15	switch name {16		vr.IsValid = v.Required(value)17		panic(fmt.Sprintf("Validation with name %s does not exist", name))18	}19}20func (v *Validation) Required(value interface{}) bool {21	if value == nil || value == "" {22	}23}

Full Screen

Full Screen

NewValidationResult

Using AI Code Generation

copy

Full Screen

1func main() {2	validation := validation.NewValidationResult()3	validation.SetRules(map[string][]string{4		"name":  {"required"},5		"email": {"required", "email"},6	})7	validation.SetData(map[string]interface{}{

Full Screen

Full Screen

NewValidationResult

Using AI Code Generation

copy

Full Screen

1func main() {2    result := validation.NewValidationResult("This is a string")3    if result.IsValid() {4        fmt.Println("The string is valid")5    } else {6        fmt.Println("The string is not valid")7    }8}9This is a guide to Packages in Go. Here we discuss how to create a package in Go, how to create a package in Go with multiple files, how to use the package in a different file, how to use the package in a different folder, how to import the package in a different folder, how to create a package with multiple files in a different folder, how to use the package in a different folder, and how to use the package in a different folder. You may also have a look at the following articles to learn more –

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful