Web App Testing – Form – Persiapan

Untuk keperluan modul ini, kita akan tambahkan form sederhana yang sudah disediakan di bootstrap pada file templates/home.page.gohtml. Berikut code yang digunakan:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
    <title>Home</title>
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col">
                <h1 class="mt-3">Home Page</h1>
                <hr>
                <form action="/login" method="post">
                <div class="mb-3">
                    <label for="email" class="form-label">Email address</label>
                    <input type="email" class="form-control" id="email" name="email">
                </div>
                <div class="mb-3">
                    <label for="password" class="form-label">Password</label>
                    <input type="password" class="form-control" id="password" name="password">
                </div>
                <button type="submit" class="btn btn-primary">Submit</button>
                </form>                
                <hr>
                <small>Your request came from {{.IP}}</small>
            </div>
        </div>
    </div>
</body>
</html>

Jika kita jalankan webapp dan buka di web browser, kurang lebih akan tampil seperti berikut:

Buka file cmd/web/handlers.go, kita tambahkan fungsi untuk handling form submit diatas.

package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"path"
)

var templatePath = "./templates/"

func (app *application) Home(w http.ResponseWriter, r *http.Request) {
	_ = app.render(w, r, "home.page.gohtml", &TemplateData{})
}

type TemplateData struct {
	IP   string
	Data map[string]any
}

func (app *application) render(w http.ResponseWriter, r *http.Request, t string, data *TemplateData) error {
	//parse template
	parsedTemplate, err := template.ParseFiles(path.Join(templatePath, t))
	if err != nil {
		http.Error(w, "bad request", http.StatusBadRequest)
		return err
	}

	//gunakan middleware yang telah kita buat.
	data.IP = app.ipFromContext(r.Context())

	//execute template
	err = parsedTemplate.Execute(w, data)
	if err != nil {
		return err
	}
	return nil
}

func (app *application) Login(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()

	if err != nil {
		log.Println(err)
		http.Error(w, "bad request", http.StatusBadRequest)
		return
	}
	email := r.Form.Get("email")
	password := r.Form.Get("password")

	log.Println(email, password)

	fmt.Fprint(w, email)
}

Kemudian buka file cmd/web/routes.go, tambahkan route untuk /login

package main

import (
	"net/http"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
)

func (app *application) routes() http.Handler {
	mux := chi.NewRouter()

	//register middleware
	mux.Use(middleware.Recoverer)
	mux.Use(app.addIPToContext) //tambahkan middleware yang kita buat

	//register routes
	mux.Get("/", app.Home)
	mux.Post("/login", app.Login)

	//static assets

	fileServer := http.FileServer(http.Dir("./static"))
	mux.Handle("/static/*", http.StripPrefix("/static/", fileServer))

	return mux
}

Selanjutnya, kita buat file cmd/web/forms.go, yang akan berisi validasi untuk form yang disubmit.

package main

import (
	"net/url"
	"strings"
)

type errors map[string][]string

func (e errors) Get(field string) string {
	errorSlice := e[field]
	if len(errorSlice) == 0 {
		return ""
	}

	return errorSlice[0]
}

func (e errors) Add(field, message string) {
	e[field] = append(e[field], message)
}

type Form struct {
	Data   url.Values
	Errors errors
}

func NewForm(data url.Values) *Form {
	return &Form{
		Data:   data,
		Errors: map[string][]string{},
	}
}

func (f *Form) Has(field string) bool {
	x := f.Data.Get(field)
	return x != ""

	// if x == "" {
	// 	return false
	// }
	// return true
}

func (f *Form) Required(fields ...string) {
	for _, field := range fields {
		value := f.Data.Get(field)
		if strings.TrimSpace(value) == "" {
			f.Errors.Add(field, "This field cannot be blank")
		}
	}
}

func (f *Form) Check(ok bool, key, message string) {
	if !ok {
		f.Errors.Add(key, message)
	}
}

func (f *Form) Valid() bool {
	return len(f.Errors) == 0
}

Setelah kode validasi dibuat, kita implementasikan pada file cmd/web/handlers.go.

package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"path"
)

var templatePath = "./templates/"

func (app *application) Home(w http.ResponseWriter, r *http.Request) {
	_ = app.render(w, r, "home.page.gohtml", &TemplateData{})
}

type TemplateData struct {
	IP   string
	Data map[string]any
}

func (app *application) render(w http.ResponseWriter, r *http.Request, t string, data *TemplateData) error {
	//parse template
	parsedTemplate, err := template.ParseFiles(path.Join(templatePath, t))
	if err != nil {
		http.Error(w, "bad request", http.StatusBadRequest)
		return err
	}

	//gunakan middleware yang telah kita buat.
	data.IP = app.ipFromContext(r.Context())

	//execute template
	err = parsedTemplate.Execute(w, data)
	if err != nil {
		return err
	}
	return nil
}

func (app *application) Login(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()

	if err != nil {
		log.Println(err)
		http.Error(w, "bad request", http.StatusBadRequest)
		return
	}

	//validation goes here
	form := NewForm(r.PostForm)
	form.Required("email", "password")

	if !form.Valid() {
		fmt.Fprint(w, "Invalid form")
		return
	}

	email := r.Form.Get("email")
	password := r.Form.Get("password")

	log.Println(email, password)

	fmt.Fprint(w, email)
}

Sampai disini, persiapan Webapp Testing Form telah selesai. Pada modul selanjutnya kita akan membuat fungsi untuk test validasi form diatas.

Sharing is caring:

Leave a Comment