fix(nextcloud-files): IN-05 Browser-Anmeldung prueft den Stand, bevor sie "abgelaufen" meldet
- antwortet die Abfrage mit 404/410, laedt die Seite zuerst den Stand neu; ging die Antwort "verbunden" unterwegs verloren, erscheinen direkt die Dateien statt eines Fehlers - Seitentest fuer den Fall Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,7 +47,8 @@ export function ConnectPanel({
|
|||||||
/** Name, Farbe und Logo der Nextcloud; solange sie fehlen, steht nur der Rechnername da. */
|
/** Name, Farbe und Logo der Nextcloud; solange sie fehlen, steht nur der Rechnername da. */
|
||||||
info?: NextcloudServerInfo | null;
|
info?: NextcloudServerInfo | null;
|
||||||
expired: boolean;
|
expired: boolean;
|
||||||
onConnected: () => void;
|
/** Verbunden (oder Stand pruefen): die Seite laedt den Stand neu. */
|
||||||
|
onConnected: () => void | Promise<void>;
|
||||||
}) {
|
}) {
|
||||||
const t = useTranslations('nextcloudFiles.connect');
|
const t = useTranslations('nextcloudFiles.connect');
|
||||||
|
|
||||||
@@ -182,7 +183,18 @@ export function ConnectPanel({
|
|||||||
if (err instanceof NextcloudFilesRequestError) {
|
if (err instanceof NextcloudFilesRequestError) {
|
||||||
if (err.status === 404 || err.status === 410) {
|
if (err.status === 404 || err.status === 410) {
|
||||||
// Abgelaufen oder unbekannt (z. B. nach einem Neustart der API): von vorn beginnen.
|
// Abgelaufen oder unbekannt (z. B. nach einem Neustart der API): von vorn beginnen.
|
||||||
stop({ code: 'flowExpired', message: err.message, retryAfterSeconds: null });
|
// Vorher den Stand neu laden (IN-05): ging die Antwort "verbunden" unterwegs verloren,
|
||||||
|
// ist das Konto in Wahrheit verbunden und die Seite zeigt gleich die Dateien.
|
||||||
|
stopped = true;
|
||||||
|
const expired: ErrorState = {
|
||||||
|
code: 'flowExpired',
|
||||||
|
message: err.message,
|
||||||
|
retryAfterSeconds: null,
|
||||||
|
};
|
||||||
|
void Promise.resolve()
|
||||||
|
.then(() => onConnectedRef.current())
|
||||||
|
.catch(() => undefined)
|
||||||
|
.finally(() => stop(expired));
|
||||||
} else if (err.code === 'nextcloudLocked' || (err.status < 500 && err.status !== 429)) {
|
} else if (err.code === 'nextcloudLocked' || (err.status < 500 && err.status !== 429)) {
|
||||||
stop(toErrorRef.current(err));
|
stop(toErrorRef.current(err));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -497,6 +497,21 @@ describe('Browser-Anmeldung', () => {
|
|||||||
expect(screen.queryByRole('link', { name: 'Anmeldung bei Nextcloud öffnen' })).toBeNull();
|
expect(screen.queryByRole('link', { name: 'Anmeldung bei Nextcloud öffnen' })).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('410/404 nach verlorener "verbunden"-Antwort: erst den Stand pruefen, dann die Dateien statt "abgelaufen" (IN-05)', async () => {
|
||||||
|
await startFlow();
|
||||||
|
const before = mockGetStatus.mock.calls.length;
|
||||||
|
mockPollFlow.mockRejectedValue(new NextcloudFilesRequestError(404, 'notFound', 'x'));
|
||||||
|
mockGetStatus.mockResolvedValue(status({ account: account({ displayName: 'Zwei Faktor' }) }));
|
||||||
|
await act(async () => {
|
||||||
|
await vi.advanceTimersByTimeAsync(2000);
|
||||||
|
});
|
||||||
|
expect(await screen.findByText('Angemeldet als Zwei Faktor')).toBeTruthy();
|
||||||
|
expect(mockGetStatus.mock.calls.length).toBeGreaterThan(before);
|
||||||
|
expect(
|
||||||
|
screen.queryByText('Die Anmeldung ist abgelaufen. Bitte starten Sie sie neu.'),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it('"failed" beendet die Abfrage und zeigt den Text', async () => {
|
it('"failed" beendet die Abfrage und zeigt den Text', async () => {
|
||||||
await startFlow();
|
await startFlow();
|
||||||
mockPollFlow.mockResolvedValue({
|
mockPollFlow.mockResolvedValue({
|
||||||
|
|||||||
Reference in New Issue
Block a user