fix: address code review on #27
- The empty state is about an empty library, not a brand-new Reader:
listView.Fresh becomes EmptyLibrary and moves behind the tab-specific
branches, so "No favourites yet" is no longer shadowed for a Reader whose
library happens to be empty. The action key stays put — hiding it was
never asked for.
- The owner is not a revocable Reader: their row offers no button and
POST /readers/{owner}/revoke is a 404, so the one row where the control
would sign out the tapping browser cannot be reached by a hand-rolled
POST either.
- Modify isolation is asserted in both directions, and the owner's own
sign-in through the OAuth callback is pinned to the seeded row.
- CUTOVER.md and REDEPLOY.md still grepped API_TOKEN out of .env for their
smoke tests, which the last commit deleted; both now take the acting
Reader's derived credential.
- Roster type follows the machine-fact spec (500 10-11px mono, tracked),
and PRODUCT.md names the Readers panel instead of claiming there is no
owner surface at all.
This commit is contained in:
@@ -119,8 +119,27 @@ func TestPerReaderIsolation(t *testing.T) {
|
||||
if err := json.Unmarshal(rr.Body.Bytes(), &owners); err != nil {
|
||||
t.Fatalf("decode: %v", err)
|
||||
}
|
||||
if len(owners) != 1 || owners[0].Title != "Solo Leveling" {
|
||||
t.Fatalf("owner list = %+v, want their own row", owners)
|
||||
if len(owners) != 1 || owners[0].Title != "Solo Leveling" || owners[0].LastChapterNum != 0 {
|
||||
t.Fatalf("owner list = %+v, want their own row at their own progress", owners)
|
||||
}
|
||||
|
||||
// The mirror: the owner's write does not move the other Reader's progress
|
||||
// either. Without it, isolation is only asserted in one direction.
|
||||
req = credRequest(http.MethodPut, "/bookmarks/"+ownerKey, ownerCredential())
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rr = httptest.NewRecorder()
|
||||
srv.ServeHTTP(rr, withBody(req, `{"key":"asura:solo","site":"asura","series_id":"solo","title":"Solo Leveling","last_chapter_num":9}`))
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("owner put: status = %d, want 200", rr.Code)
|
||||
}
|
||||
rr = httptest.NewRecorder()
|
||||
srv.ServeHTTP(rr, credRequest(http.MethodGet, "/bookmarks", readerCredential("other-reader")))
|
||||
var theirs3 []store.Bookmark
|
||||
if err := json.Unmarshal(rr.Body.Bytes(), &theirs3); err != nil {
|
||||
t.Fatalf("decode: %v", err)
|
||||
}
|
||||
if len(theirs3) != 1 || theirs3[0].LastChapterNum != 3 {
|
||||
t.Fatalf("other reader list = %+v, want progress 3 after the owner's write", theirs3)
|
||||
}
|
||||
|
||||
// DELETE is scoped to its caller too, asserted in both directions: each
|
||||
|
||||
Reference in New Issue
Block a user