widgetAnmelden({ id, titel, wo, sichtbar, laden, leer, inhalt, takt }) —
der Rahmen macht daraus ein Fenster in der Spalte (Terminal) oder ein
Schild (Desktop), kennt lädt/fertig/nichts da/Fehler und haelt den
Nachladetakt. Benutzer, Wetter und Systemzustand sind umgestellt; aus
index.html sind vier feste Kaesten verschwunden und aus dem Raster die
Einzelplaetze.
Zwei Dinge, die erst dabei sichtbar wurden:
- Der Server meldete 'kein Ort eingestellt' und 'Dienst nicht
erreichbar' beide als 204. Ein Ausfall sah damit aus wie ein
abgeschaltetes Widget. Ausfall ist jetzt 502, mit Test.
- Die Reihenfolge haengt nicht mehr an der Modulauswertung: Seit
glyphs.js seine Raster mit await auf oberster Ebene laedt, laufen
Module ohne Symbole vorher durch — der Systemzustand stand deshalb
ueber dem Benutzer. widgetsOrdnen() macht die Reihenfolge zur Angabe,
und genau dort haengt spaeter die im Server gespeicherte ein.
131 lines
4.2 KiB
Go
131 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"honeyos/internal/store"
|
|
"honeyos/internal/weather"
|
|
)
|
|
|
|
// Ohne eingestellten Ort ist 204 die richtige Antwort: kein Fehler, nur nichts
|
|
// zu zeigen. Die Leiste lässt das Symbol dann weg, statt etwas zu melden.
|
|
func TestOhneOrtGibtEsKeinWetter(t *testing.T) {
|
|
s := newTestServer(t, "") // ohne Anbieter: offener Betrieb, kein Anmelden nötig
|
|
s.wetter = weather.FakeFuerTest(t, 0, 20)
|
|
|
|
rec := httptest.NewRecorder()
|
|
s.routes().ServeHTTP(rec, httptest.NewRequest("GET", "/api/weather", nil))
|
|
if rec.Code != http.StatusNoContent {
|
|
t.Fatalf("ohne Ort erwartet 204, bekam %d", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestMitOrtKommtDasWetter(t *testing.T) {
|
|
s := newTestServer(t, "")
|
|
s.wetter = weather.FakeFuerTest(t, 3, 8.6)
|
|
if err := s.store.SetSettings(store.LocalSub, map[string]string{
|
|
"weatherCity": "Köln", "weatherLat": "50.938", "weatherLon": "6.96",
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
rec := httptest.NewRecorder()
|
|
s.routes().ServeHTTP(rec, httptest.NewRequest("GET", "/api/weather", nil))
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("erwartet 200, bekam %d: %s", rec.Code, rec.Body)
|
|
}
|
|
var w weather.Wetter
|
|
json.Unmarshal(rec.Body.Bytes(), &w)
|
|
if w.Ort != "Köln" || w.Glyph != "wolke" {
|
|
t.Fatalf("falsches Wetter: %+v", w)
|
|
}
|
|
}
|
|
|
|
// Ist ein Ort eingestellt und der Dienst fällt aus, ist das etwas anderes als
|
|
// „nichts eingestellt": Es gibt etwas zu zeigen, es kommt nur gerade nicht. Die
|
|
// Oberfläche unterscheidet das — 204 verschwindet still, 502 sagt „nicht
|
|
// erreichbar". Beides als 204 zu melden hiess: Ein Ausfall sah aus wie ein
|
|
// abgeschaltetes Widget.
|
|
func TestAusfallIstNichtDasselbeWieNichts(t *testing.T) {
|
|
s := newTestServer(t, "")
|
|
s.wetter = weather.KaputtFuerTest(t)
|
|
if err := s.store.SetSettings(store.LocalSub, map[string]string{
|
|
"weatherCity": "Köln", "weatherLat": "50.938", "weatherLon": "6.96",
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
rec := httptest.NewRecorder()
|
|
s.routes().ServeHTTP(rec, httptest.NewRequest("GET", "/api/weather", nil))
|
|
if rec.Code != http.StatusBadGateway {
|
|
t.Fatalf("bei Ausfall erwartet 502, bekam %d", rec.Code)
|
|
}
|
|
}
|
|
|
|
// Der Streifen in der Leiste heisst .apps und blendet seine rechten 18 Pixel
|
|
// mit einer Maske aus. Bekommt ein zweites Element dieselbe Klasse, erbt es die
|
|
// Maske — die Schublade sah rechts aus, als loese sie sich auf, und in der
|
|
// Geometrie war nichts zu sehen. Deshalb hier festgenagelt.
|
|
func TestNurDerStreifenHeisstApps(t *testing.T) {
|
|
b, err := os.ReadFile("web/honeybar/honeybar.js")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
src := string(b)
|
|
|
|
for _, verboten := range []string{`class="menu apps"`, `class="apps menu"`} {
|
|
if strings.Contains(src, verboten) {
|
|
t.Errorf("%s: Das Menue erbt damit die Ausblendmaske des App-Streifens", verboten)
|
|
}
|
|
}
|
|
// Genau ein Element darf die Klasse tragen: der Streifen selbst.
|
|
if n := strings.Count(src, `class="apps"`); n != 1 {
|
|
t.Errorf(`class="apps" kommt %dx vor, erwartet genau einmal (der Streifen)`, n)
|
|
}
|
|
}
|
|
|
|
// Die HoneyBar bringt ihr CSS und ihr Markup in Vorlagenzeichenketten mit.
|
|
// Ein Backtick in einem Kommentar beendet die Zeichenkette mittendrin — die
|
|
// Datei ist dann kaputt, und zwar nur in der HoneyBar, nicht auf dem
|
|
// Schreibtisch. Genau das ist zweimal passiert; deshalb dieser Wächter.
|
|
func TestHoneyBarOhneBacktickInKommentaren(t *testing.T) {
|
|
b, err := os.ReadFile("web/honeybar/honeybar.js")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
src := string(b)
|
|
|
|
imBlock := false
|
|
for nr, zeile := range strings.Split(src, "\n") {
|
|
rest := zeile
|
|
for {
|
|
if imBlock {
|
|
ende := strings.Index(rest, "*/")
|
|
if ende < 0 {
|
|
if strings.Contains(rest, "`") {
|
|
t.Errorf("Zeile %d: Backtick in einem Kommentar — das beendet die Vorlagenzeichenkette:\n %s", nr+1, strings.TrimSpace(zeile))
|
|
}
|
|
break
|
|
}
|
|
if strings.Contains(rest[:ende], "`") {
|
|
t.Errorf("Zeile %d: Backtick in einem Kommentar — das beendet die Vorlagenzeichenkette:\n %s", nr+1, strings.TrimSpace(zeile))
|
|
}
|
|
rest = rest[ende+2:]
|
|
imBlock = false
|
|
continue
|
|
}
|
|
start := strings.Index(rest, "/*")
|
|
if start < 0 {
|
|
break
|
|
}
|
|
rest = rest[start+2:]
|
|
imBlock = true
|
|
}
|
|
}
|
|
}
|