fix(community): Label-ID im Veröffentlichen-Dialog, Status nie in „lädt“, Nachprüfung robust
Die Überschrift des Dialogs hatte dieselbe ID wie das Titelfeld (publish-title), das Label des Pflichtfelds zeigte damit auf die Überschrift; jetzt publish-heading. Schließt der Browser den Dialog mitten im Senden, wird er wieder geöffnet statt als abgebrochen aufgelöst. Die Status-Abfrage der Seite wird bei einer lokalen Änderung während der Anfrage wiederholt (nie in „lädt“ hängen), die Nachprüfung nach offenem Ausgang ist eine eigene Abfrage. Der Löschen-Dialog nennt bei unbekanntem Status einen allgemeinen Hinweis und sagt, dass sich eine Veröffentlichung nur auf der Community-Seite zurückziehen lässt. publishCard heißt lokal publishWithCheck. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f6b9ee61f4
commit
87b71ec71f
4 files changed
+216
-33
No files matched your search
@@ -768,16 +768,77 @@ describe('Meine Karten: Veröffentlichung (Status an der Kachel)', () => {
|
||||
expect(mocks.myPublications).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('Löschen einer veröffentlichten Karte weist darauf hin, dass die Veröffentlichung bleibt', async () => {
|
||||
await mountWith(pubMap(published('g1', 'a')));
|
||||
button(tileFor('a'), 'Löschen').click();
|
||||
const GENERIC_HINT =
|
||||
'Falls diese Karte veröffentlicht ist, bleibt die Veröffentlichung bestehen – zurückziehen kannst du sie auf ihrer Community-Seite.';
|
||||
const openDelete = async (id: string) => {
|
||||
button(tileFor(id), 'Löschen').click();
|
||||
await vi.waitFor(() => expect(dialog()?.open).toBe(true));
|
||||
};
|
||||
|
||||
it('Löschen einer veröffentlichten Karte (Status bekannt) nennt, dass die Veröffentlichung bleibt und wo man sie zurückzieht', async () => {
|
||||
await mountWith(pubMap(published('g1', 'a')));
|
||||
await openDelete('a');
|
||||
expect(dialog()!.textContent).toContain('bleibt in der Community-Galerie');
|
||||
expect(dialog()!.textContent).toContain('Community-Seite');
|
||||
expect(dialog()!.textContent).not.toContain('Falls diese Karte');
|
||||
button(dialog()!, 'Abbrechen').click();
|
||||
await vi.waitFor(() => expect(dialog()).toBeNull());
|
||||
button(tileFor('b'), 'Löschen').click();
|
||||
// Bekannt unveröffentlicht: kein Hinweis.
|
||||
await vi.waitFor(() => expect(button(tileFor('b'), 'Löschen').disabled).toBe(false));
|
||||
await openDelete('b');
|
||||
expect(dialog()!.textContent).not.toContain('Community');
|
||||
});
|
||||
|
||||
it('Löschen, solange der Status noch lädt: allgemeiner Hinweis', async () => {
|
||||
mocks.list.mockResolvedValue([card('a', 'Alpha')]);
|
||||
mocks.myPublications.mockReturnValue(new Promise(() => {}));
|
||||
mount();
|
||||
await vi.waitFor(() => expect(tiles()).toHaveLength(1));
|
||||
await openDelete('a');
|
||||
expect(dialog()!.textContent).toContain(GENERIC_HINT);
|
||||
});
|
||||
|
||||
it('Löschen, wenn der Status nicht geladen werden konnte: allgemeiner Hinweis', async () => {
|
||||
mocks.list.mockResolvedValue([card('a', 'Alpha')]);
|
||||
mocks.myPublications.mockRejectedValue(new TypeError('offline'));
|
||||
mount();
|
||||
await vi.waitFor(() => expect(text()).toContain('konnte nicht geladen werden'));
|
||||
await openDelete('a');
|
||||
expect(dialog()!.textContent).toContain(GENERIC_HINT);
|
||||
});
|
||||
|
||||
it('Status-Abfrage, die ein gleichzeitiges Zurückziehen überholt, lässt den Status nie in „lädt“ hängen', async () => {
|
||||
mocks.list.mockResolvedValue([card('a', 'Alpha'), card('b', 'Beta')]);
|
||||
mocks.myPublications.mockRejectedValueOnce(new TypeError('offline'));
|
||||
mount();
|
||||
await vi.waitFor(() => expect(text()).toContain('konnte nicht geladen werden'));
|
||||
await vi.waitFor(() => expect(labels(tileFor('a'))).toContain('Veröffentlichen'));
|
||||
// Im Fehlerzustand lässt sich veröffentlichen; danach gibt es „Zurückziehen“.
|
||||
mocks.publishSavedCard.mockResolvedValue({ id: 'g9' });
|
||||
await openPublish('a');
|
||||
fillDialog();
|
||||
sendForm();
|
||||
await vi.waitFor(() => expect(badge('a')).toBe('Veröffentlicht'));
|
||||
// Zurückziehen läuft (Anfrage unterwegs) ...
|
||||
let finishWithdraw!: () => void;
|
||||
mocks.withdrawCard.mockReturnValue(new Promise<void>((r) => (finishWithdraw = r)));
|
||||
await vi.waitFor(() => expect(button(tileFor('a'), 'Zurückziehen').disabled).toBe(false));
|
||||
button(tileFor('a'), 'Zurückziehen').click();
|
||||
await vi.waitFor(() => expect(dialog()?.open).toBe(true));
|
||||
expect(dialog()!.textContent).not.toContain('Community-Galerie');
|
||||
button(dialog()!, 'Zurückziehen').click();
|
||||
await vi.waitFor(() => expect(mocks.withdrawCard).toHaveBeenCalledWith('g9'));
|
||||
// ... währenddessen „Nochmal versuchen“ (die Abfrage hängt noch) ...
|
||||
let finishFetch!: (m: Map<string, GalleryCard>) => void;
|
||||
mocks.myPublications.mockReturnValueOnce(new Promise((r) => (finishFetch = r)));
|
||||
button(root, 'Nochmal versuchen').click();
|
||||
expect(labels(tileFor('b'))).not.toContain('Veröffentlichen'); // Status gilt wieder als unbekannt
|
||||
// ... und das Zurückziehen wird fertig, bevor die Abfrage antwortet.
|
||||
finishWithdraw();
|
||||
await vi.waitFor(() => expect(badge('a')).toBe(''));
|
||||
finishFetch(new Map());
|
||||
await vi.waitFor(() => expect(labels(tileFor('b'))).toContain('Veröffentlichen'));
|
||||
expect(labels(tileFor('a'))).toContain('Veröffentlichen');
|
||||
expect(text()).not.toContain('konnte nicht geladen werden');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -941,6 +1002,31 @@ describe('Meine Karten: Veröffentlichen', () => {
|
||||
expect(badge('a')).toBe('');
|
||||
});
|
||||
|
||||
it('die Nachprüfung geht nicht verloren, wenn währenddessen eine andere Kachel ihren Status ändert', async () => {
|
||||
mocks.publishSavedCard.mockRejectedValue(new ApiError(503, 'Der Dienst ist gerade nicht erreichbar.'));
|
||||
mocks.withdrawCard.mockResolvedValue(undefined);
|
||||
mocks.list.mockResolvedValue([card('a', 'Alpha'), card('b', 'Beta')]);
|
||||
mocks.myPublications.mockResolvedValue(new Map([['b', published('g2', 'b')]]));
|
||||
mount();
|
||||
await vi.waitFor(() => expect(tiles()).toHaveLength(2));
|
||||
await vi.waitFor(() => expect(labels(tileFor('b'))).toContain('Zurückziehen'));
|
||||
await openPublish('a');
|
||||
fillDialog();
|
||||
let finishCheck!: (m: Map<string, GalleryCard>) => void;
|
||||
mocks.myPublications.mockReturnValueOnce(new Promise((r) => (finishCheck = r)));
|
||||
sendForm();
|
||||
await vi.waitFor(() => expect(mocks.myPublications).toHaveBeenCalledTimes(2));
|
||||
// Während die Nachprüfung läuft, zieht der Nutzer in einer anderen Kachel eine Karte zurück.
|
||||
button(tileFor('b'), 'Zurückziehen').click();
|
||||
await vi.waitFor(() => expect(dialog()?.open).toBe(true));
|
||||
button(dialog()!, 'Zurückziehen').click();
|
||||
await vi.waitFor(() => expect(labels(tileFor('b'))).toContain('Veröffentlichen'));
|
||||
finishCheck(new Map([['a', published('g1', 'a')]]));
|
||||
await vi.waitFor(() => expect(badge('a')).toBe('Veröffentlicht'));
|
||||
expect(publishDialogEl()).toBeNull();
|
||||
expect(tileFor('a').querySelector('.card-msg')!.textContent).toBe('');
|
||||
});
|
||||
|
||||
it('die Nachprüfung findet nur die Veröffentlichung dieser Karte (eine andere zählt nicht)', async () => {
|
||||
mocks.publishSavedCard.mockRejectedValue(new ApiError(503, 'Der Dienst ist gerade nicht erreichbar.'));
|
||||
await start();
|
||||
@@ -950,7 +1036,7 @@ describe('Meine Karten: Veröffentlichen', () => {
|
||||
sendForm();
|
||||
await vi.waitFor(() => expect(dlgError()).toContain('Der Dienst ist gerade nicht erreichbar.'));
|
||||
expect(badge('a')).toBe('');
|
||||
expect(badge('b')).toBe('Veröffentlicht');
|
||||
expect(dlgError()).toContain('Der Dienst ist gerade nicht erreichbar.');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user