Skip to content

Commit eb49629

Browse files
authored
Merge pull request #559 from Chris0Jeky/fix/520-board-restore-success-toast
fix: add success toast after board restore (#520)
2 parents 244c274 + 3a0dea1 commit eb49629

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

backend/tests/Taskdeck.Api.Tests/RateLimitingApiTests.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,17 @@ public async Task AuthEndpoints_ShouldThrottleAfterBurst_ByClientIp()
4040
[Fact]
4141
public async Task AuthEndpoints_ShouldRecoverAfterWindowReset()
4242
{
43+
// Use a 3-second window so CI slowness cannot reset the window between the
44+
// setup request and the throttle probe — one permit is consumed by the first
45+
// SendInvalidLoginAsync call and the window must stay active long enough for
46+
// SendInvalidLoginUntilThrottledAsync to observe the 429.
4347
using var factory = CreateFactoryWithRateLimits(
4448
authPermitLimit: 1,
45-
authWindowSeconds: 1);
49+
authWindowSeconds: 3);
4650
using var client = factory.CreateClient();
4751

4852
(await SendInvalidLoginAsync(client)).StatusCode.Should().Be(HttpStatusCode.Unauthorized);
49-
var throttled = await SendInvalidLoginUntilThrottledAsync(client);
53+
var throttled = await SendInvalidLoginUntilThrottledAsync(client, maxAttempts: 15);
5054
var retryAfterSeconds = await AssertThrottleContractAsync(throttled, RateLimitingPolicyNames.AuthPerIp);
5155
using var recovered = await SendInvalidLoginUntilRecoveredAsync(client, retryAfterSeconds);
5256
recovered.StatusCode.Should().Be(HttpStatusCode.Unauthorized);

frontend/taskdeck-web/src/tests/views/ArchiveView.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,37 @@ describe('ArchiveView', () => {
231231
setItemSpy.mockRestore()
232232
})
233233

234+
it('shows error toast when board restore fails', async () => {
235+
const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(true)
236+
237+
mocks.getBoards.mockResolvedValue([
238+
{
239+
id: 'board-archived',
240+
name: 'Failing Board',
241+
description: null,
242+
isArchived: true,
243+
createdAt: new Date().toISOString(),
244+
updatedAt: new Date().toISOString(),
245+
},
246+
])
247+
mocks.updateBoard.mockRejectedValue(new Error('network error'))
248+
249+
const wrapper = mount(ArchiveView)
250+
await waitForAsyncUi()
251+
252+
const restoreBoardButton = findButtonByText(wrapper, 'Restore Board')
253+
await restoreBoardButton.trigger('click')
254+
await waitForAsyncUi()
255+
256+
expect(mocks.updateBoard).toHaveBeenCalledWith('board-archived', { isArchived: false })
257+
expect(mocks.successToast).not.toHaveBeenCalled()
258+
expect(mocks.errorToast).toHaveBeenCalledWith('Failed to restore board')
259+
// Board remains in the list
260+
expect(wrapper.findAll('.td-archive-list--section .td-archive-row')).toHaveLength(1)
261+
262+
confirmSpy.mockRestore()
263+
})
264+
234265
it('hides archived board from default list and reveals it when hidden toggle is enabled', async () => {
235266
mocks.getBoards.mockResolvedValue([
236267
{

0 commit comments

Comments
 (0)