fix(cards): Editor an Karte und Konto koppeln (Neue Karte, Abmelden, Kontowechsel)
- Editor zeigt „Bearbeitet: <Name>“, solange eine gespeicherte Karte gebunden ist, und bietet „Neue Karte“ (setzt zurück, bricht Laden ab, entfernt ?karte=; fragt bei ungespeicherten Änderungen per eigenem Dialog „Verwerfen?“) - EditorState.savedConfig als Vergleichsbasis für ungespeicherte Änderungen - bindEditorToAuth: Abmelden leert den Editor, Kontowechsel A -> B entkoppelt die Karte (Entwurf bleibt), Anmelden ohne Vorgänger und abgelaufene Sitzung behalten den Entwurf; auth.onLogout unterscheidet eigenes Abmelden von bemerktem Ablauf - Speichern nimmt den Schnappschuss pro Klick (auch für die Wiederholung nach 401) - save: row_not_found beim Update legt eine neue Karte an (inkl. Aufräumen) - Karten-Seite: Editor-Abgleich auch nach dem Verlassen der Seite, Löschen-Dialog wird beim Verlassen geschlossen, keine doppelten Vorschau-URLs - confirm-dialog als gemeinsames Modul (Löschen, Verwerfen) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ba4d9f76d4
commit
38b361ad7a
20 files changed
+1038
-116
No files matched your search
@@ -251,6 +251,60 @@ describe('logout', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('onLogout', () => {
|
||||
it('wird nach dem eigenen Abmelden aufgerufen, auch wenn die Sitzung schon weg war (401)', async () => {
|
||||
const auth = await freshAuth();
|
||||
const fn = vi.fn();
|
||||
auth.onLogout(fn);
|
||||
mocks.deleteSession.mockResolvedValueOnce({});
|
||||
await auth.logout();
|
||||
expect(fn).toHaveBeenCalledTimes(1);
|
||||
mocks.deleteSession.mockRejectedValueOnce(fail(401, 'general_unauthorized_scope'));
|
||||
await auth.logout();
|
||||
expect(fn).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('wird nicht aufgerufen, wenn nur eine abgelaufene Sitzung bemerkt wird (getCurrentUser → 401)', async () => {
|
||||
const auth = await freshAuth();
|
||||
mocks.get.mockResolvedValueOnce({ $id: 'u1', email: 'a@b.de' });
|
||||
await auth.getCurrentUser();
|
||||
const fn = vi.fn();
|
||||
const change = vi.fn();
|
||||
auth.onLogout(fn);
|
||||
auth.onAuthChange(change);
|
||||
mocks.get.mockRejectedValueOnce(fail(401, 'general_unauthorized_scope'));
|
||||
await auth.getCurrentUser();
|
||||
expect(change).toHaveBeenCalledWith(null);
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('wird nicht aufgerufen, wenn das Abmelden scheitert, und auch nicht beim Login mit alter Sitzung', async () => {
|
||||
const auth = await freshAuth();
|
||||
const fn = vi.fn();
|
||||
auth.onLogout(fn);
|
||||
mocks.deleteSession.mockRejectedValueOnce(new TypeError('Failed to fetch'));
|
||||
await expect(auth.logout()).rejects.toBeInstanceOf(TypeError);
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
|
||||
mocks.createEmailPasswordSession
|
||||
.mockRejectedValueOnce(fail(409, 'user_session_already_exists'))
|
||||
.mockResolvedValueOnce({});
|
||||
mocks.deleteSession.mockResolvedValueOnce({});
|
||||
mocks.get.mockResolvedValue({ $id: 'u2', email: 'b@b.de' });
|
||||
await auth.login('b@b.de', 'geheim123');
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('gibt eine Abmelde-Funktion zurück', async () => {
|
||||
const auth = await freshAuth();
|
||||
const fn = vi.fn();
|
||||
auth.onLogout(fn)();
|
||||
mocks.deleteSession.mockResolvedValue({});
|
||||
await auth.logout();
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('onAuthChange', () => {
|
||||
it('gibt eine Abmelde-Funktion zurück', async () => {
|
||||
const auth = await freshAuth();
|
||||
|
||||
Reference in new issue
Block a user