e2e

package module
v0.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 4, 2025 License: MIT Imports: 14 Imported by: 0

README

GitHub tag GitHub code size in bytes

Go-e2e

This is just a small library I mainly wrote over a couple of days this weekend to test my own HTTP APIs. It's only written for my own personal gain. It's not tested and it only supports my own narrow set of requrements.

Go-e2e was written to be a quick and concurrent facilitator of HTTP API tests.

Go-e2e is a library, meaning it has no main function. To use it you create an empty go-module with a main fuction, create a Runner and call Run on a list of test sets you've declared yourself.

import (
	"github.com/gomsim/go-e2e"
)

func main() {
	e2e.Runner{}.Run(
		AuthSuite,
		EmailSuite,
		NotificationsSuite,
		UsersSuite,

		LoginSequence,
		RegisterUserSequence,
		CreateEventSequence,
	)
}

When you run your app you will be presented with a progress bar which when filled will give way to a result summary as well as a prompt giving you the option to see only the logs of failed tests cases or to see the logs of all performed tests (lots of text).

Successful run

But what is a "test"?

Tests

So the whole point of the library is its ability to run test cases. Each Test consists of a Setup and an Expect. The setup describes the details of a single HTTP call to be made. The expect describes expectations of the HTTP response. Tests which receive HTTP responses that don't meet the expectations count as failures.

e2e.Test{
    Setup: e2e.Setup{
        Method: "GET",
        URL:    "mydomain.com/ping",
    },
    Expect: e2e.Expect{
        Status: 200,
    },
}

Suites

To make testing somewhat feasible and organized tests can be gathered in sets of type Suite. A suite has a name and is a set of independent named tests with no order.

e2e.Suite{
	Name: "myService",
	Tests: e2e.Tests{
		"ping": {
			Setup: e2e.Setup{
				Method: "GET",
				URL:    "mydomain.com/ping",
			},
			Expect: e2e.Expect{
				Status: 200,
			},
		},
		"create": {
			Setup: e2e.Setup{
				Method: "POST",
				URL:    "mydomain.com/creatething",
			},
			Expect: e2e.Expect{
				Status: 201,
			},
		},
		"auth": {
			Setup: e2e.Setup{
				Method: "POST",
				URL:    "mydomain.com/login",
				Body:   `{"user": "username", "password": "password"}`,
			},
			Expect: e2e.Expect{
				Status: 200,
				Headers: e2e.Headers{
					{"Set-Cookie", "session_id=abc123xyz"},
				},
			},
		},
	},
}

Sequences

Some tests require some setup. Or perhaps testing of one HTTP request requires information contained in the response to a different HTTP request. This is where type Sequences comes in. Sequences resemble suites in that they have a name and a collection of tests, but have some other nice features. A sequence is, well sequential, meaning tests are run in the order they are declared. Tests within sequences are also of type Step. This is because tests, or steps, in a sequence are not indipendent but interdependent. While a suite test can only contain a setup and expectations a sequence step can also take input and give output. There are two ways to do this. A manual InputFunc or a Captor. They share a likeness under the hood, but have different use cases. An input func is declared within a step if the step requires some external information in order to be performed, such as a pin code or some other information retrieved from a third source. When the tests are run the opportunity will be presented for the user to input the data as needed. Captors on the other hand are declared within a step to let it capture information contained within its HTTP response, such as an oid or URL, and let subsequent steps reference it to perform their own HTTP calls.

e2e.Sequence{
	Name: "finger print - order flow",
	Steps: []e2e.Step{
		{
			Setup: e2e.Setup{
				Method:  "POST",
				URL:     "mydomain.com/fingerprint/create",
				Content: "application/json",
				Body:    `{"user": "MyUser", "phone": "010111000",}`,
			},
			Expect: e2e.Expect{
				Status: 201,
				Fields: e2e.Fields{
					"message": "OK"
				},
			},
		},
		{
			Inputs: []e2e.InputFunc{
				e2e.Input("finger print", "fingerprint"), // Propmpts the user for "finger print" and stores the input in a memory location called "fingerprint"
			},
			Setup: e2e.Setup{
				Method:  "POST",
				URL:     "mydomain.com/fingerprint/apply",
				Content: "application/json",
				Body:    `{"print": "$fingerprint"}`, // References the stored "fingerprint"
			},
			Expect: e2e.Expect{
				Status: 200,
				Fields: e2e.Fields{
					"token": "",
				},
			},
			Capture: e2e.Captors{"token"}, // Captures whatever was the value of the "token" field in the response body
		},
		{
			Setup: e2e.Setup{
				Method:  "POST",
				URL:     "mydomain.com/auth/token",
				Headers: e2e.Headers{{Key: "Authorization", Val: "Bearer $token"}}, // References the stored "token"
			},
			Expect: e2e.Expect{
				Status: 200,
				Fields: e2e.Fields{
					"url": "",
				},
			},
			Capture: e2e.Captors{"url"}, // Captures whatever was the value of the "url" field in the response body
		},
		{
			Setup: e2e.Setup{
				Method: "POST",
				URL:    "$url", // References the stored "url"
			},
			Expect: e2e.Expect{
				Status: 200,
			},
		},
	},
}

Concurrency and performance

From my own manual testing it seems to scale pretty constantly and run whatever amount of tests in about a second, though it's only been tested on at most about 130 tests in one go.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Command

func Command(command string, args ...string) func(data map[string]string) (string, error)

func Input

func Input(text string, mapTo string) func(data map[string]string) (string, error)

Types

type Before

type Before []func(data map[string]string) (string, error)

type Body

type Body map[string]any

type Captors

type Captors []string

type Expect

type Expect struct {
	Status  int
	Headers Headers
	Body    Body
}

type Headers

type Headers []header

type Request

type Request struct {
	CTX     context.Context
	Method  string
	URL     string
	Headers Headers
	Content string
	Body    string
}

type Runner

type Runner struct {
	BeforeRun func() any
	AfterRun  func(any)
}

func (Runner) Run

func (r Runner) Run(sets ...set)

type Sequence

type Sequence struct {
	Name  string
	Steps Steps
}

type Steps

type Steps []test

type Suite

type Suite struct {
	Name  string
	Tests Tests
}

type Tests

type Tests map[string]test

Directories

Path Synopsis
cmd
e2r command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL