rastrillo / pwa Public

Clone
git clone https://amadan.net/rastrillo/pwa

Plain git — no account needed to clone.

Download

Download this file

1package pwa
2
3import (
4 "encoding/json"
5 "net/http"
6 "net/http/httptest"
7 "strings"
8 "testing"
9)
10
11func exampleManifest() Manifest {
12 return Manifest{ID: "/app/", Name: "Example", StartURL: "/app/inbox", Scope: "/app/",
13 Icons: []Icon{{Src: "/icon.png", Sizes: "192x192", Type: "image/png"}}}
14}
15
16func TestManifestIdentityAndHeaders(t *testing.T) {
17 m := exampleManifest()
18 m.Name = `Example "quoted" <app>`
19 h, err := m.Handler()
20 if err != nil {
21 t.Fatal(err)
22 }
23 w := httptest.NewRecorder()
24 h.ServeHTTP(w, httptest.NewRequest("GET", "/manifest.webmanifest", nil))
25 var got Manifest
26 if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil {
27 t.Fatal(err)
28 }
29 if got.ID != m.ID || got.Name != m.Name || got.Display != "standalone" {
30 t.Fatalf("identity changed: %+v", got)
31 }
32 if w.Header().Get("Content-Type") != "application/manifest+json" || w.Header().Get("Cache-Control") != "no-cache" {
33 t.Fatal(w.Header())
34 }
35 for _, method := range []string{"HEAD", "POST"} {
36 w := httptest.NewRecorder()
37 h.ServeHTTP(w, httptest.NewRequest(method, "/manifest.webmanifest", nil))
38 if method == "HEAD" && w.Body.Len() != 0 {
39 t.Fatal("HEAD returned a body")
40 }
41 if method == "POST" && w.Code != http.StatusMethodNotAllowed {
42 t.Fatal("manifest accepted a mutation")
43 }
44 }
45}
46
47func TestManifestRejectsScopeEscapes(t *testing.T) {
48 for _, start := range []string{"/other/", "//evil.example/", "/app/../outside", "/app/%2e%2e/outside", "/app/%5c../outside", "/app/./inbox", "/app/\n/", "https://example.com/app/"} {
49 t.Run(start, func(t *testing.T) {
50 m := exampleManifest()
51 m.StartURL = start
52 if _, err := m.Handler(); err == nil {
53 t.Fatalf("accepted ambiguous or out-of-scope start URL %q", start)
54 }
55 })
56 }
57}
58
59func TestAssetsAreScriptsAndNeverDirectoryListings(t *testing.T) {
60 h := http.StripPrefix("/pwa", Assets())
61 for _, path := range []string{"/pwa/client.mjs", "/pwa/worker.js"} {
62 w := httptest.NewRecorder()
63 h.ServeHTTP(w, httptest.NewRequest("GET", path, nil))
64 if w.Code != 200 || !strings.HasPrefix(w.Header().Get("Content-Type"), "text/javascript") || w.Body.Len() == 0 {
65 t.Fatalf("%s: %d %v", path, w.Code, w.Header())
66 }
67 }
68 w := httptest.NewRecorder()
69 h.ServeHTTP(w, httptest.NewRequest("GET", "/pwa/", nil))
70 if w.Code != 404 {
71 t.Fatal("assets exposed a directory listing")
72 }
73}
74