How to use FilePath method of config Package

Best Gauge code snippet using config.FilePath

config_provider.go

Source:config_provider.go Github

copy

Full Screen

...45 }46 return configProvider47}48func (c *configProvider) GetForDir(dirPath string) (Config, error) {49 filePath, err := c.GetFilePathForDir(dirPath)50 if err != nil {51 return Config{}, err52 }53 if filePath == "" {54 return getDefaultConfig(c.develMode, dirPath)55 }56 return c.Get(filePath)57}58func (c *configProvider) GetFilePathForDir(dirPath string) (string, error) {59 if !filepath.IsAbs(dirPath) {60 return "", fmt.Errorf("%s is not an absolute path", dirPath)61 }62 return getFilePathForDir(filepath.Clean(dirPath))63}64func (c *configProvider) Get(filePath string) (Config, error) {65 if !filepath.IsAbs(filePath) {66 return Config{}, fmt.Errorf("%s is not an absolute path", filePath)67 }68 filePath = filepath.Clean(filePath)69 return get(c.develMode, filePath)70}71func (c *configProvider) GetForData(dirPath string, externalConfigData string) (Config, error) {72 if !filepath.IsAbs(dirPath) {73 return Config{}, fmt.Errorf("%s is not an absolute path", dirPath)74 }75 dirPath = filepath.Clean(dirPath)76 var externalConfig ExternalConfig77 if err := jsonUnmarshalStrict([]byte(externalConfigData), &externalConfig); err != nil {78 return Config{}, err79 }80 return externalConfigToConfig(c.develMode, externalConfig, dirPath)81}82func (c *configProvider) GetExcludePrefixesForDir(dirPath string) ([]string, error) {83 if !filepath.IsAbs(dirPath) {84 return nil, fmt.Errorf("%s is not an absolute path", dirPath)85 }86 dirPath = filepath.Clean(dirPath)87 return getExcludePrefixesForDir(dirPath)88}89func (c *configProvider) GetExcludePrefixesForData(dirPath string, externalConfigData string) ([]string, error) {90 if !filepath.IsAbs(dirPath) {91 return nil, fmt.Errorf("%s is not an absolute path", dirPath)92 }93 dirPath = filepath.Clean(dirPath)94 var externalConfig ExternalConfig95 if err := jsonUnmarshalStrict([]byte(externalConfigData), &externalConfig); err != nil {96 return nil, err97 }98 return getExcludePrefixes(externalConfig.Excludes, dirPath)99}100// getFilePathForDir tries to find a file named by one of the ConfigFilenames starting in the101// given directory, and going up a directory until hitting root.102//103// The directory must be an absolute path.104//105// If no such file is found, "" is returned.106// If multiple files named by one of the ConfigFilenames are found in the same107// directory, error is returned.108func getFilePathForDir(dirPath string) (string, error) {109 for {110 filePath, err := getSingleFilePathForDir(dirPath)111 if err != nil {112 return "", err113 }114 if filePath != "" {115 return filePath, nil116 }117 if dirPath == "/" {118 return "", nil119 }120 dirPath = filepath.Dir(dirPath)121 }122}123// getSingleFilePathForDir gets the file named by one of the ConfigFilenames in the124// given directory. Having multiple such files results in an error being returned. If no file is125// found, this returns "".126func getSingleFilePathForDir(dirPath string) (string, error) {127 var filePaths []string128 for _, configFilename := range ConfigFilenames {129 filePath := filepath.Join(dirPath, configFilename)130 if _, err := os.Stat(filePath); err == nil {131 filePaths = append(filePaths, filePath)132 }133 }134 switch len(filePaths) {135 case 0:136 return "", nil137 case 1:138 return filePaths[0], nil139 default:140 return "", fmt.Errorf("multiple configuration files in the same directory: %v", filePaths)141 }142}143// get reads the config at the given path.144//145// This is expected to be in YAML or JSON format, which is denoted by the file extension.146func get(develMode bool, filePath string) (Config, error) {147 externalConfig, err := getExternalConfig(filePath)148 if err != nil {149 return Config{}, err150 }151 return externalConfigToConfig(develMode, externalConfig, filepath.Dir(filePath))152}153func getDefaultConfig(develMode bool, dirPath string) (Config, error) {154 return externalConfigToConfig(develMode, ExternalConfig{}, dirPath)155}156func getExternalConfig(filePath string) (ExternalConfig, error) {157 data, err := ioutil.ReadFile(filePath)158 if err != nil {159 return ExternalConfig{}, err160 }161 if len(data) == 0 {162 return ExternalConfig{}, nil163 }164 externalConfig := ExternalConfig{}165 switch filepath.Ext(filePath) {166 case ".json":167 if err := jsonUnmarshalStrict(data, &externalConfig); err != nil {168 return ExternalConfig{}, err169 }170 return externalConfig, nil171 case ".yaml":172 if err := yaml.UnmarshalStrict(data, &externalConfig); err != nil {173 return ExternalConfig{}, err174 }175 return externalConfig, nil176 default:177 return ExternalConfig{}, fmt.Errorf("unknown config file extension, must be .json or .yaml: %s", filePath)178 }179}180// externalConfigToConfig converts an ExternalConfig to a Config.181//182// This will return a valid Config, or an error.183func externalConfigToConfig(develMode bool, e ExternalConfig, dirPath string) (Config, error) {184 excludePrefixes, err := getExcludePrefixes(e.Excludes, dirPath)185 if err != nil {186 return Config{}, err187 }188 includePaths := make([]string, 0, len(e.Protoc.Includes))189 for _, includePath := range strs.SortUniq(e.Protoc.Includes) {190 if !filepath.IsAbs(includePath) {191 includePath = filepath.Join(dirPath, includePath)192 }193 includePath = filepath.Clean(includePath)194 includePaths = append(includePaths, includePath)195 }196 ignoreIDToFilePaths := make(map[string][]string)197 for _, ignore := range e.Lint.Ignores {198 id := strings.ToUpper(ignore.ID)199 for _, protoFilePath := range ignore.Files {200 if !filepath.IsAbs(protoFilePath) {201 protoFilePath = filepath.Join(dirPath, protoFilePath)202 }203 protoFilePath = filepath.Clean(protoFilePath)204 if _, ok := ignoreIDToFilePaths[id]; !ok {205 ignoreIDToFilePaths[id] = make([]string, 0)206 }207 ignoreIDToFilePaths[id] = append(ignoreIDToFilePaths[id], protoFilePath)208 }209 }210 genPlugins := make([]GenPlugin, len(e.Generate.Plugins))211 for i, plugin := range e.Generate.Plugins {212 genPluginType, err := ParseGenPluginType(plugin.Type)213 if err != nil {214 return Config{}, err215 }216 if plugin.Output == "" {217 return Config{}, fmt.Errorf("output path required for plugin %s", plugin.Name)218 }219 var relPath, absPath string220 if filepath.IsAbs(plugin.Output) {221 absPath = filepath.Clean(plugin.Output)222 relPath, err = filepath.Rel(dirPath, absPath)223 if err != nil {224 return Config{}, fmt.Errorf("failed to resolve plugin %q output absolute path %q to a relative path with base %q: %v", plugin.Name, absPath, dirPath, err)225 }226 } else {227 relPath = plugin.Output228 absPath = filepath.Clean(filepath.Join(dirPath, relPath))229 }230 if plugin.FileSuffix != "" && plugin.FileSuffix[0] == '.' {231 return Config{}, fmt.Errorf("file_suffix begins with '.' but should not include the '.': %s", plugin.FileSuffix)232 }233 if plugin.Name != "descriptor_set" {234 if plugin.IncludeImports {235 return Config{}, fmt.Errorf("include_imports is only valid for the descriptor_set plugin but set on %q", plugin.Name)236 }237 if plugin.IncludeSourceInfo {238 return Config{}, fmt.Errorf("include_source_info is only valid for the descriptor_set plugin but set on %q", plugin.Name)239 }240 }241 genPlugins[i] = GenPlugin{242 Name: plugin.Name,243 GetPath: getPluginPathFunc(plugin.Path),244 Type: genPluginType,245 Flags: plugin.Flags,246 FileSuffix: plugin.FileSuffix,247 IncludeImports: plugin.IncludeImports,248 IncludeSourceInfo: plugin.IncludeSourceInfo,249 OutputPath: OutputPath{250 RelPath: relPath,251 AbsPath: absPath,252 },253 }254 }255 sort.Slice(genPlugins, func(i int, j int) bool { return genPlugins[i].Name < genPlugins[j].Name })256 createDirPathToBasePackage := make(map[string]string)257 for _, pkg := range e.Create.Packages {258 relDirPath := pkg.Directory259 basePackage := pkg.Name260 if relDirPath == "" {261 return Config{}, fmt.Errorf("directory for create package is empty")262 }263 if basePackage == "" {264 return Config{}, fmt.Errorf("name for create package is empty")265 }266 if filepath.IsAbs(relDirPath) {267 return Config{}, fmt.Errorf("directory for create package must be relative: %s", relDirPath)268 }269 createDirPathToBasePackage[filepath.Clean(filepath.Join(dirPath, relDirPath))] = basePackage270 }271 // to make testing easier272 if len(createDirPathToBasePackage) == 0 {273 createDirPathToBasePackage = nil274 }275 var fileHeader string276 if e.Lint.FileHeader.Path != "" || e.Lint.FileHeader.Content != "" {277 if e.Lint.FileHeader.Path != "" && e.Lint.FileHeader.Content != "" {278 return Config{}, fmt.Errorf("must only specify either file header path or content")279 }280 var fileHeaderContent string281 if e.Lint.FileHeader.Path != "" {282 if filepath.IsAbs(e.Lint.FileHeader.Path) {283 return Config{}, fmt.Errorf("path for file header must be relative: %s", e.Lint.FileHeader.Path)284 }285 fileHeaderData, err := ioutil.ReadFile(filepath.Join(dirPath, e.Lint.FileHeader.Path))286 if err != nil {287 return Config{}, err288 }289 fileHeaderContent = string(fileHeaderData)290 } else { // if e.Lint.FileHeader.Content != ""291 fileHeaderContent = e.Lint.FileHeader.Content292 }293 fileHeaderLines := getFileHeaderLines(fileHeaderContent)294 if !e.Lint.FileHeader.IsCommented {295 for i, fileHeaderLine := range fileHeaderLines {296 if fileHeaderLine == "" {297 fileHeaderLines[i] = "//"298 } else {299 fileHeaderLines[i] = "// " + fileHeaderLine300 }301 }302 }303 fileHeader = strings.Join(fileHeaderLines, "\n")304 if fileHeader == "" {305 return Config{}, fmt.Errorf("file header path or content specified but result was empty file header")306 }307 }308 if !develMode {309 if e.Lint.AllowSuppression {310 return Config{}, fmt.Errorf("allow_suppression is not allowed outside of internal prototool tests")311 }312 }313 config := Config{314 DirPath: dirPath,315 ExcludePrefixes: excludePrefixes,316 Compile: CompileConfig{317 ProtobufVersion: e.Protoc.Version,318 IncludePaths: includePaths,319 IncludeWellKnownTypes: true, // Always include the well-known types.320 AllowUnusedImports: e.Protoc.AllowUnusedImports,321 },322 Create: CreateConfig{323 DirPathToBasePackage: createDirPathToBasePackage,324 },325 Lint: LintConfig{326 IncludeIDs: strs.SortUniqModify(e.Lint.Rules.Add, strings.ToUpper),327 ExcludeIDs: strs.SortUniqModify(e.Lint.Rules.Remove, strings.ToUpper),328 Group: strings.ToLower(e.Lint.Group),329 NoDefault: e.Lint.Rules.NoDefault,330 IgnoreIDToFilePaths: ignoreIDToFilePaths,331 FileHeader: fileHeader,332 JavaPackagePrefix: e.Lint.JavaPackagePrefix,333 AllowSuppression: e.Lint.AllowSuppression,334 },335 Break: BreakConfig{336 IncludeBeta: e.Break.IncludeBeta,337 AllowBetaDeps: e.Break.AllowBetaDeps,338 },339 Gen: GenConfig{340 GoPluginOptions: GenGoPluginOptions{341 ImportPath: e.Generate.GoOptions.ImportPath,342 ExtraModifiers: e.Generate.GoOptions.ExtraModifiers,343 },344 Plugins: genPlugins,345 },346 }347 for _, genPlugin := range config.Gen.Plugins {348 // TODO: technically protoc-gen-protoc-gen-foo is a valid349 // plugin binary with name protoc-gen-foo, but do we want350 // to error if protoc-gen- is a prefix of a name?351 // I think this will be a common enough mistake that we352 // can remove this later. Or, do we want names to include353 // the protoc-gen- part?354 if strings.HasPrefix(genPlugin.Name, "protoc-gen-") {355 return Config{}, fmt.Errorf("plugin name provided was %s, do not include the protoc-gen- prefix", genPlugin.Name)356 }357 if _, ok := _genPluginTypeToString[genPlugin.Type]; !ok {358 return Config{}, fmt.Errorf("unknown GenPluginType: %v", genPlugin.Type)359 }360 if (genPlugin.Type.IsGo() || genPlugin.Type.IsGogo()) && config.Gen.GoPluginOptions.ImportPath == "" {361 return Config{}, fmt.Errorf("go plugin %s specified but no import path provided", genPlugin.Name)362 }363 }364 if intersection := strs.Intersection(config.Lint.IncludeIDs, config.Lint.ExcludeIDs); len(intersection) > 0 {365 return Config{}, fmt.Errorf("config had intersection of %v between lint_include and lint_exclude", intersection)366 }367 return config, nil368}369func getExcludePrefixesForDir(dirPath string) ([]string, error) {370 filePath, err := getSingleFilePathForDir(dirPath)371 if err != nil {372 return nil, err373 }374 if filePath == "" {375 return []string{}, nil376 }377 externalConfig, err := getExternalConfig(filePath)378 if err != nil {379 return nil, err380 }381 return getExcludePrefixes(externalConfig.Excludes, dirPath)382}383func getExcludePrefixes(excludes []string, dirPath string) ([]string, error) {384 excludePrefixes := make([]string, 0, len(excludes))...

Full Screen

Full Screen

config_test.go

Source:config_test.go Github

copy

Full Screen

...21var testDir string22func TestNewInstanceConfig(t *testing.T) {23 setup(t)24 defer teardown()25 expectedFilePath := filepath.Join(testDir, "fake-machine.json")26 cfg, _ := NewInstanceConfig(expectedFilePath)27 if cfg.FilePath != expectedFilePath {28 t.Errorf("Expected path '%s'. Received '%s'", expectedFilePath, cfg.FilePath)29 }30 if _, err := os.Stat(cfg.FilePath); os.IsNotExist(err) {31 t.Errorf("File %s should exists", cfg.FilePath)32 }33}34func TestConfigOnFileExists(t *testing.T) {35 setup(t)36 defer teardown()37 filePath := filepath.Join(testDir, "fake-machine.json")38 expectedOcPath := filepath.Join(testDir, "fakeOc")39 cfg := &InstanceConfigType{40 FilePath: filePath,41 OcPath: expectedOcPath,42 }43 jsonData, _ := json.MarshalIndent(cfg, "", "\t")44 // create config file before NewInstanceConfig45 ioutil.WriteFile(cfg.FilePath, jsonData, 0644)46 newCfg, _ := NewInstanceConfig(filePath)47 if newCfg.OcPath != expectedOcPath {48 t.Errorf("Expected oc path '%s'. Received '%s'", expectedOcPath, cfg.OcPath)49 }50}51func TestWrite(t *testing.T) {52 setup(t)53 defer teardown()54 path := filepath.Join(testDir, "fake-machine.json")55 cfg, _ := NewInstanceConfig(path)56 expectedOcPath := filepath.Join(testDir, "fakeOc")57 cfg.OcPath = expectedOcPath58 cfg.Write()59 // read config file and verify content60 var testCfg *InstanceConfigType61 raw, err := ioutil.ReadFile(path)62 if err != nil {63 t.Errorf("Error reading config file %s", path)64 }65 json.Unmarshal(raw, &testCfg)66 if testCfg.OcPath != cfg.OcPath {67 t.Errorf("Expected oc path '%s'. Received '%s'", expectedOcPath, cfg.OcPath)68 }69}70func TestDelete(t *testing.T) {71 setup(t)72 defer teardown()73 path := filepath.Join(testDir, "fake-machine.json")74 cfg, _ := NewInstanceConfig(path)75 cfg.Delete()76 if _, err := os.Stat(cfg.FilePath); err == nil {77 t.Errorf("Expected file '%s' to be deleted", path)78 }79}80func setup(t *testing.T) {81 var err error82 testDir, err = ioutil.TempDir("", "minishift-test-config-")83 if err != nil {84 t.Error(err)85 }86}87// teardown remove the temp directory88func teardown() {89 os.RemoveAll(testDir)90}...

Full Screen

Full Screen

geheim_benchmark_helpers.go

Source:geheim_benchmark_helpers.go Github

copy

Full Screen

1package testhelpers2import "treuzedev/geheim/packages/config"3func CleanUpBenchmarkTesfiles(benchmarkConfig config.Config) {4 for _, filepath := range benchmarkConfig.Files {5 RemoveTestFile(filepath)6 }7}8func SetupBenchmarksEncryption() (benchmarkConfig config.Config) {9 files := []struct {10 filepath string11 data string12 }{13 {14 filepath: "file0",15 data: GetTestfile0D(),16 },17 {18 filepath: "file1",19 data: GetTestfile1D(),20 },21 {22 filepath: "file2",23 data: GetTestfile2D(),24 },25 }26 filepaths := []string{}27 for _, file := range files {28 GenerateTestFiles(file.data, file.filepath)29 filepaths = append(filepaths, file.filepath)30 }31 return config.Config{32 Check: "",33 SecretKey: "imsosecret",34 Encrypt: true,35 Decrypt: false,36 Files: filepaths,37 }38}39func SetupBenchmarksDecryption() (benchmarkConfig config.Config) {40 files := []struct {41 filepath string42 data string43 }{44 {45 filepath: "file0",46 data: GetTestfile0E(),47 },48 {49 filepath: "file1",50 data: GetTestfile1E(),51 },52 {53 filepath: "file2",54 data: GetTestfile2E(),55 },56 }57 filepaths := []string{}58 for _, file := range files {59 GenerateTestFiles(file.data, file.filepath)60 filepaths = append(filepaths, file.filepath)61 }62 return config.Config{63 Check: "",64 SecretKey: "imsosecret",65 Encrypt: false,66 Decrypt: true,67 Files: filepaths,68 }69}70func SetupBenchmarksCheckDecrypted() (benchmarkConfig config.Config) {71 files := []struct {72 filepath string73 data string74 }{75 {76 filepath: "file0",77 data: GetTestfile0D(),78 },79 {80 filepath: "file1",81 data: GetTestfile1D(),82 },83 {84 filepath: "file2",85 data: GetTestfile2D(),86 },87 }88 filepaths := []string{}89 for _, file := range files {90 GenerateTestFiles(file.data, file.filepath)91 filepaths = append(filepaths, file.filepath)92 }93 return config.Config{94 Check: "d",95 SecretKey: "",96 Encrypt: true,97 Decrypt: false,98 Files: filepaths,99 }100}101func SetupBenchmarksCheckEncrypted() (benchmarkConfig config.Config) {102 files := []struct {103 filepath string104 data string105 }{106 {107 filepath: "file0",108 data: GetTestfile0E(),109 },110 {111 filepath: "file1",112 data: GetTestfile1E(),113 },114 {115 filepath: "file2",116 data: GetTestfile2E(),117 },118 }119 filepaths := []string{}120 for _, file := range files {121 GenerateTestFiles(file.data, file.filepath)122 filepaths = append(filepaths, file.filepath)123 }124 return config.Config{125 Check: "e",126 SecretKey: "",127 Encrypt: true,128 Decrypt: false,129 Files: filepaths,130 }131}...

Full Screen

Full Screen

FilePath

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 config, err := config.NewConfig("ini", "conf/app.conf")4 if err != nil {5 fmt.Println("new config failed, err:", err)6 }7 filePath := config.Path()8 fmt.Println("config path:", filePath)9}10func (c *ConfigContainer) Path() string {11}

Full Screen

Full Screen

FilePath

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 conf, err := config.NewConfig("ini", "config.ini")4 if err != nil {5 fmt.Println(err)6 }7 fmt.Println(conf.String("appname"))8 fmt.Println(conf.String("httpport"))9 fmt.Println(conf.String("mysql::user"))10 fmt.Println(conf.String("mysql::password"))11 fmt.Println(conf.String("mysql::port"))12 fmt.Println(conf.String("mysql::database"))13 fmt.Println(conf.String("redis::port"))14 fmt.Println(conf.String("redis::host"))15 fmt.Println(conf.String("redis::password"))16 fmt.Println(conf.String("redis::database"))17 fmt.Println(conf.String("mongodb::port"))18 fmt.Println(conf.String("mongodb::host"))19 fmt.Println(conf.String("mongodb::password"))20 fmt.Println(conf.String("mongodb::database"))21 fmt.Println(conf.String("mongodb::maxpoolsize"))22 fmt.Println(conf.String("mongodb::minpoolsize"))23}24import (25func main() {26 conf, err := config.NewConfig("ini", "config.ini")27 if err != nil {28 fmt.Println(err)29 }30 fmt.Println(conf.String("appname"))31 fmt.Println(conf.String("httpport"))32 fmt.Println(conf.String("mysql::user"))33 fmt.Println(conf.String("mysql::password"))34 fmt.Println(conf.String("mysql::port"))35 fmt.Println(conf.String("mysql::database"))36 fmt.Println(conf.String("redis::port"))37 fmt.Println(conf.String("redis::host"))38 fmt.Println(conf.String("redis::password"))39 fmt.Println(conf.String("redis::database"))40 fmt.Println(conf.String("mongodb::port"))41 fmt.Println(conf.String("mongodb::host"))42 fmt.Println(conf.String("mongodb::password"))43 fmt.Println(conf.String("mongodb::database"))44 fmt.Println(conf.String("mongodb::maxpoolsize"))45 fmt.Println(conf.String("mongodb::minpoolsize"))46 s, _ := conf.DIY("mysql")47 fmt.Println(s)48 s, _ = conf.DIY("redis")49 fmt.Println(s)50 s, _ = conf.DIY("mongodb")51 fmt.Println(s)

Full Screen

Full Screen

FilePath

Using AI Code Generation

copy

Full Screen

1import (2type Config struct {3}4func main() {5 if _, err := toml.DecodeFile("config.toml", &config); err != nil {6 fmt.Println(err)7 }8 fmt.Println(config.Path)9}10import (11type Config struct {12}13func main() {14 if _, err := toml.DecodeFile("config.toml", &config); err != nil {15 fmt.Println(err)16 }17 fmt.Println(config.Path)18}19import (20type Config struct {21}22func main() {23 if _, err := toml.DecodeFile("config.toml", &config); err != nil {24 fmt.Println(err)25 }26 fmt.Println(config.Path)27}28import (29type Config struct {30}31func main() {32 if _, err := toml.DecodeFile("config.toml", &config); err != nil {33 fmt.Println(err)34 }35 fmt.Println(config.Path)36}37import (38type Config struct {39}40func main() {41 if _, err := toml.DecodeFile("config.toml", &config); err != nil {42 fmt.Println(err)43 }44 fmt.Println(config.Path)45}46import (47type Config struct {48}49func main() {

Full Screen

Full Screen

FilePath

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 fmt.Println(viper.GetString("name"))4 fmt.Println(viper.GetString("age"))5 fmt.Println(viper.GetString("address"))6 fmt.Println(viper.GetString("phone"))7 fmt.Println(viper.GetString("email"))8}

Full Screen

Full Screen

FilePath

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 fmt.Println(config.FilePath())4}5import (6func FilePath() string {7 dir, err := filepath.Abs(filepath.Dir(os.Args[0]))8 if err != nil {9 }10}11import (12func main() {13 fmt.Println(config.CurrentDir())14}15import (16func CurrentDir() string {17 dir, err := os.Getwd()18 if err != nil {19 }20}21import (22func main() {23 fmt.Println(config.CurrentDir())24}25import (26func CurrentDir() string {27 dir, err := filepath.Abs(filepath.Dir(os.Args[0]))28 if err != nil {29 }30}

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