diff --git a/README.md b/README.md
index 87ac6d17986684565ddae99f0406643f6f2b4545..56c5fce1c5abd0b2976ccb64aefa9e62793dadf6 100644
--- a/README.md
+++ b/README.md
@@ -1,38 +1,47 @@
 # xxdk-WASM
 
-WebAssembly bindings for xxDK.
+This repository contains the WebAssembly bindings for xxDK. It also includes a
+test server to serve the compiled WebAssembly module.
 
 ## Building
 
+The repository can only be compiled to a WebAssembly binary using `GOOS=js` and
+`GOARCH=wasm`.
+
 ```shell
 $ GOOS=js GOARCH=wasm go build -o xxdk.wasm
 ```
 
-### Running Tests
-
-To run unit tests, you need to first install
-[wasmbrowsertest](https://github.com/agnivade/wasmbrowsertest).
+### Running Unit Tests
 
-`wasm/wasm_js.s` contains commands only recognized by the Go WebAssembly
-compiler and thus cause compile errors when running tests. It needs to be
-excluded when running tests.
+Because the bindings use `syscall/js`, tests cannot only be run in a browser. To
+automate this process first install
+[wasmbrowsertest](https://github.com/agnivade/wasmbrowsertest). Then, tests can
+be run using the following command.
 
 ```shell
-$ GOOS=js GOARCH=wasm go test
+$ GOOS=js GOARCH=wasm go test ./...
 ```
 
+Note, this will fail because `wasm/wasm_js.s` contains commands only recognized
+by the Go WebAssembly compiler and for some reason not recognized by the test
+runner. To get tests to run, temporarily delete the body of `wasm/wasm_js.s`
+during testing.
+
 ## Testing
 
-The `test` directory contains a website and server to run the compiled
-WebAssembly module. `assets` contains the website and `server` contains a small
-Go HTTP server.
+The `test` directory contains `assets`, a simple web page to run the Javascript,
+and `server`, which runs a simple Go HTTP server to deliver the webpage.
+
+To run the server, first compile the bindings and save them to the `assets`
+directory. Then run the server
 
 ```shell
 $ GOOS=js GOARCH=wasm go build -o test/assets/xxdk.wasm
 $ go run test/server/main.go
 ```
 
-### `wasm_exec.js`
+## `wasm_exec.js`
 
 `wasm_exec.js` is provided by Go and is used to import the WebAssembly module in
 the browser. It can be retrieved from Go using the following command.
diff --git a/wasm/backup.go b/wasm/backup.go
index 33a3edcf4ce134f7bf968b377966e447891ce403..94ebaad4f140e0f6775bcb29efd70747f3227908 100644
--- a/wasm/backup.go
+++ b/wasm/backup.go
@@ -51,9 +51,9 @@ func (ubf *updateBackupFunc) UpdateBackup(encryptedBackup []byte) {
 // Client functions                                                           //
 ////////////////////////////////////////////////////////////////////////////////
 
-// NewCmixFromBackup initializes a new e2e storage from an encrypted
-// backup. Users of this function should delete the storage directory on error.
-// Users of this function should call LoadCmix as normal once this call succeeds.
+// NewCmixFromBackup initializes a new e2e storage from an encrypted backup.
+// Users of this function should delete the storage directory on error. Users of
+// this function should call LoadCmix as normal once this call succeeds.
 //
 // Parameters:
 //  - args[0] - JSON of the NDF (string).
diff --git a/wasm/broadcast.go b/wasm/broadcast.go
index 65152f1b054fa02840e43141d29f03cf0e863cff..2efc02512db1b988e81d89be53d839ce78894257 100644
--- a/wasm/broadcast.go
+++ b/wasm/broadcast.go
@@ -14,6 +14,8 @@ import (
 	"syscall/js"
 )
 
+// Channel wraps the [bindings.Channel] object so its methods can be wrapped to
+// be Javascript compatible.
 type Channel struct {
 	api *bindings.Channel
 }
diff --git a/wasm/delivery.go b/wasm/delivery.go
index 8bf3dcbe79a272cb2cd206e2457042bca78de1fe..603d692273c4a044bc3b5676576c4c691981fb3f 100644
--- a/wasm/delivery.go
+++ b/wasm/delivery.go
@@ -24,9 +24,10 @@ func (mdc *messageDeliveryCallback) EventCallback(
 	mdc.eventCallback(delivered, timedOut, CopyBytesToJS(roundResults))
 }
 
-// WaitForRoundResult allows the caller to get notified if the rounds a message was sent in successfully completed. Under the hood, this uses an API
-// that uses the internal round data, network historical round lookup, and
-// waiting on network events to determine what has (or will) occur.
+// WaitForRoundResult allows the caller to get notified if the rounds a message
+// was sent in successfully completed. Under the hood, this uses an API that
+// uses the internal round data, network historical round lookup, and waiting on
+// network events to determine what has (or will) occur.
 //
 // This function takes the marshaled send report to ensure a memory leak does
 // not occur as a result of both sides of the bindings holding a reference to
diff --git a/wasm/dummy.go b/wasm/dummy.go
index 449facb27aa4a872bd99b25de5a81295fe08b098..33b9b8118b7478d0d958d4fe50a473459bc9aae6 100644
--- a/wasm/dummy.go
+++ b/wasm/dummy.go
@@ -33,11 +33,11 @@ func newDummyTrafficJS(newDT *bindings.DummyTraffic) map[string]interface{} {
 }
 
 // NewDummyTrafficManager creates a DummyTraffic manager and initialises the
-// dummy traffic sending thread. Note that the manager does not start sending dummy
-// traffic until `True` is passed into DummyTraffic.SetStatus. The time duration
-// between each sending operation and the amount of messages sent each interval
-// are randomly generated values with bounds defined by the
-// given parameters below.
+// dummy traffic sending thread. Note that the manager does not start sending
+// dummy traffic until true is passed into DummyTraffic.SetStatus. The time
+// duration between each sending operation and the amount of messages sent each
+// interval are randomly generated values with bounds defined by the given
+// parameters below.
 //
 // Parameters:
 //  - args[0] - a Cmix object ID in the tracker (int).
@@ -45,9 +45,9 @@ func newDummyTrafficJS(newDT *bindings.DummyTraffic) map[string]interface{} {
 //    sending cycle (int).
 //  - args[2] - the average duration, in milliseconds, to wait between sends
 //    (int).
-//  - args[3] - the upper bound of the interval between sending cycles,
-//    in milliseconds (int). Sends occur every average send (args[2]) +/- a
-//    random duration with an upper bound of args[3].
+//  - args[3] - the upper bound of the interval between sending cycles, in
+//    milliseconds. Sends occur every average send (args[2]) +/- a random
+//    duration with an upper bound of args[3] (int).
 //
 // Returns:
 //  - Javascript representation of the DummyTraffic object.
@@ -71,8 +71,8 @@ func NewDummyTrafficManager(_ js.Value, args []js.Value) interface{} {
 // once that operation has completed.
 //
 // Parameters:
-//  - args[0] - Input should be true if you want to send dummy messages and false
-//    if you want to pause dummy messages (boolean).
+//  - args[0] - Input should be true if you want to send dummy messages and
+//    false if you want to pause dummy messages (boolean).
 //
 // Returns:
 //  - Throws a TypeError if the DummyTraffic.SetStatus is called too frequently,
diff --git a/wasm/e2e.go b/wasm/e2e.go
index b0f79041b943bfeca08d0726a6a90d8897f06ee7..cc28db341524fa17fb1914fdc54970b6efcac7d7 100644
--- a/wasm/e2e.go
+++ b/wasm/e2e.go
@@ -111,7 +111,7 @@ func Login(_ js.Value, args []js.Value) interface{} {
 //
 // Parameters:
 //  - args[0] - ID of Cmix object in tracker (int).
-//  - args[1] - Javascript object that has functions that implement the.
+//  - args[1] - Javascript object that has functions that implement the
 //    [bindings.AuthCallbacks] interface.
 //  - args[2] - JSON of the [xxdk.ReceptionIdentity] object (Uint8Array).
 //  - args[3] - JSON of [xxdk.E2EParams] (Uint8Array).
@@ -210,19 +210,22 @@ func newAuthCallbacks(value js.Value) *authCallbacks {
 	return a
 }
 
-func (a *authCallbacks) Request(contact, receptionId []byte, ephemeralId, roundId int64) {
+func (a *authCallbacks) Request(
+	contact, receptionId []byte, ephemeralId, roundId int64) {
 	if a.request != nil {
 		a.request(contact, receptionId, ephemeralId, roundId)
 	}
 }
 
-func (a *authCallbacks) Confirm(contact, receptionId []byte, ephemeralId, roundId int64) {
+func (a *authCallbacks) Confirm(
+	contact, receptionId []byte, ephemeralId, roundId int64) {
 	if a.confirm != nil {
 		a.confirm(contact, receptionId, ephemeralId, roundId)
 	}
 
 }
-func (a *authCallbacks) Reset(contact, receptionId []byte, ephemeralId, roundId int64) {
+func (a *authCallbacks) Reset(
+	contact, receptionId []byte, ephemeralId, roundId int64) {
 	if a.reset != nil {
 		a.reset(contact, receptionId, ephemeralId, roundId)
 	}
diff --git a/wasm/group.go b/wasm/group.go
index d75c10a5624a4b9235930b9564be5d602e16f220..4fd74d2142ad141047ac978a9c98f52421fb247a 100644
--- a/wasm/group.go
+++ b/wasm/group.go
@@ -32,6 +32,7 @@ func newGroupChatJS(api *bindings.GroupChat) map[string]interface{} {
 		"MakeGroup":     js.FuncOf(gc.MakeGroup),
 		"ResendRequest": js.FuncOf(gc.ResendRequest),
 		"JoinGroup":     js.FuncOf(gc.JoinGroup),
+		"LeaveGroup":    js.FuncOf(gc.LeaveGroup),
 		"Send":          js.FuncOf(gc.Send),
 		"GetGroups":     js.FuncOf(gc.GetGroups),
 		"GetGroup":      js.FuncOf(gc.GetGroup),
diff --git a/wasm/utils.go b/wasm/utils.go
index 7b0e32df9b70b854ec1263ee9a307447ff47022d..ea4695626442060f48e0ea30f75f988c8d7bc4d1 100644
--- a/wasm/utils.go
+++ b/wasm/utils.go
@@ -14,18 +14,23 @@ import (
 	"syscall/js"
 )
 
+// CopyBytesToGo copies the Uint8Array stored in the js.Value to []byte. This is
+// a wrapper for js.CopyBytesToGo to make it more convenient.
 func CopyBytesToGo(src js.Value) []byte {
 	b := make([]byte, src.Length())
 	js.CopyBytesToGo(b, src)
 	return b
 }
 
+// CopyBytesToJS copies the []byte to a Uint8Array stored in a js.Value. This is
+// a wrapper for js.CopyBytesToJS to make it more convenient.
 func CopyBytesToJS(src []byte) js.Value {
 	dst := js.Global().Get("Uint8Array").New(len(src))
 	js.CopyBytesToJS(dst, src)
 	return dst
 }
 
+// JsonToJS converts a marshalled JSON bytes to a Javascript object.
 func JsonToJS(src []byte) js.Value {
 	var inInterface map[string]interface{}
 	err := json.Unmarshal(src, &inInterface)
@@ -37,9 +42,12 @@ func JsonToJS(src []byte) js.Value {
 	return js.ValueOf(inInterface)
 }
 
-// Throw function stub to throws Javascript exceptions.
+// Throw function stub to throws Javascript exceptions. The exception must be
+// one of the defined Exception below.  Any other error types will result in an
+// error.
 func Throw(exception Exception, message string)
 
+// Exception are the possible Javascript error types that can be thrown.
 type Exception string
 
 const (