-
Notifications
You must be signed in to change notification settings - Fork 0
[PB-5978]: feat(mail)/frozen account state #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
e081bd6
0b4390a
99d313d
05bbaea
f8202bb
eba51ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,7 @@ import { beforeEach, afterEach, describe, expect, test, vi } from 'vitest'; | |
| import { SdkManager } from '..'; | ||
| import { MailService } from '.'; | ||
| import { getMockedMails, getMockedMailBoxes, getMockedMail } from '@/test-utils/fixtures'; | ||
| import type { SetupMailAccountPayload } from '@internxt/sdk/dist/mail/types'; | ||
| import type { MailAccountResponse, SetupMailAccountPayload } from '@internxt/sdk/dist/mail/types'; | ||
|
|
||
| describe('Mail Service', () => { | ||
| beforeEach(() => { | ||
|
|
@@ -14,6 +14,53 @@ describe('Mail Service', () => { | |
| vi.restoreAllMocks(); | ||
| }); | ||
|
|
||
| describe('Get me', () => { | ||
| test('When fetching the mail account and it is active, then the account should be returned', async () => { | ||
| const mockAccount: MailAccountResponse = { | ||
| id: 'account-1', | ||
| defaultAddress: 'jane@inxt.me', | ||
| status: 'active', | ||
| }; | ||
| const mockMailClient = { | ||
| getMailAccount: vi.fn().mockResolvedValue(mockAccount), | ||
| } as any; | ||
| vi.spyOn(SdkManager.instance, 'getMail').mockReturnValue(mockMailClient); | ||
|
|
||
| const result = await MailService.instance.getMe(); | ||
|
|
||
| expect(result).toStrictEqual(mockAccount); | ||
| expect(mockMailClient.getMailAccount).toHaveBeenCalledOnce(); | ||
| }); | ||
|
|
||
| test('When fetching the mail account and it is suspended, then suspendedAt and deletionAt should be present', async () => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using technical descriptions. |
||
| const mockAccount: MailAccountResponse = { | ||
| id: 'account-1', | ||
| defaultAddress: 'jane@inxt.me', | ||
| status: 'suspended', | ||
| suspendedAt: '2026-05-01T00:00:00.000Z', | ||
| deletionAt: '2026-06-01T00:00:00.000Z', | ||
| }; | ||
| const mockMailClient = { | ||
| getMailAccount: vi.fn().mockResolvedValue(mockAccount), | ||
| } as any; | ||
| vi.spyOn(SdkManager.instance, 'getMail').mockReturnValue(mockMailClient); | ||
|
|
||
| const result = await MailService.instance.getMe(); | ||
|
|
||
| expect(result).toStrictEqual(mockAccount); | ||
| }); | ||
|
|
||
| test('When fetching the mail account fails, then an error should be thrown', async () => { | ||
| const unexpectedError = new Error('Unauthorized'); | ||
| const mockMailClient = { | ||
| getMailAccount: vi.fn().mockRejectedValue(unexpectedError), | ||
| } as any; | ||
| vi.spyOn(SdkManager.instance, 'getMail').mockReturnValue(mockMailClient); | ||
|
|
||
| await expect(MailService.instance.getMe()).rejects.toThrow(unexpectedError); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Get mailboxes info', () => { | ||
| test('When fetching mailboxes, then all mailboxes should be returned', async () => { | ||
| const mockedMailboxes = getMockedMailBoxes(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ import { | |
| FetchListFolderError, | ||
| FetchMailAccountKeysError, | ||
| FetchMailboxesInfoError, | ||
| FetchMailMeError, | ||
| FetchMessageError, | ||
| MAIL_NOT_SETUP_CODE, | ||
| MailNotSetupError, | ||
|
|
@@ -60,6 +61,45 @@ describe('Mail API', () => { | |
| vi.clearAllMocks(); | ||
| }); | ||
|
|
||
| describe('Get Mail Me', () => { | ||
| test('When fetching the mail account and it is active, then it should return the account data', async () => { | ||
| const mockAccount = { id: 'account-1', defaultAddress: 'jane@inxt.me', status: 'active' as const }; | ||
| vi.spyOn(MailService.instance, 'getMe').mockResolvedValue(mockAccount); | ||
| const store = createTestStore(); | ||
|
|
||
| const result = await store.dispatch(mailApi.endpoints.getMailMe.initiate()); | ||
|
|
||
| expect(result.data).toStrictEqual(mockAccount); | ||
| }); | ||
|
|
||
| test('When fetching the mail account and it is suspended, then it should return the suspended account', async () => { | ||
| const mockAccount = { | ||
| id: 'account-1', | ||
| defaultAddress: 'jane@inxt.me', | ||
| status: 'suspended' as const, | ||
| suspendedAt: '2026-05-01T00:00:00.000Z', | ||
| deletionAt: '2026-06-01T00:00:00.000Z', | ||
| }; | ||
| vi.spyOn(MailService.instance, 'getMe').mockResolvedValue(mockAccount); | ||
| const store = createTestStore(); | ||
|
|
||
| const result = await store.dispatch(mailApi.endpoints.getMailMe.initiate()); | ||
|
|
||
| expect(result.data).toStrictEqual(mockAccount); | ||
| }); | ||
|
|
||
| test('When fetching the mail account fails, then a FetchMailMeError should be returned', async () => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can use |
||
| vi.spyOn(MailService.instance, 'getMe').mockRejectedValue(new Error('Network error')); | ||
| const castErrorSpy = vi.spyOn(ErrorService.instance, 'castError'); | ||
| const store = createTestStore(); | ||
|
|
||
| const result = await store.dispatch(mailApi.endpoints.getMailMe.initiate()); | ||
|
|
||
| expect(castErrorSpy).toHaveBeenCalledOnce(); | ||
| expect(result.error).toBeInstanceOf(FetchMailMeError); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Get Mailboxes', () => { | ||
| test('When getting the mailboxes, then it should return the list of mailboxes', async () => { | ||
| const mockedMailboxes = getMockedMailBoxes(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; | ||
| import { getDaysUntil } from '.'; | ||
|
|
||
| describe('Calculating the days remaining until a future date', () => { | ||
| beforeEach(() => { | ||
| vi.useFakeTimers(); | ||
| vi.setSystemTime(new Date('2026-05-11T12:00:00.000Z')); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| vi.useRealTimers(); | ||
| }); | ||
|
|
||
| test('When no date is provided, then it should return undefined', () => { | ||
| const result = getDaysUntil(undefined); | ||
|
|
||
| expect(result).toBeUndefined(); | ||
| }); | ||
|
|
||
| test('When the date is several days in the future, then it should return the rounded-up day count', () => { | ||
| const result = getDaysUntil('2026-05-16T12:00:00.000Z'); | ||
|
|
||
| expect(result).toBe(5); | ||
| }); | ||
|
|
||
| test('When the date is less than a full day in the future, then it should round up to 1', () => { | ||
| const result = getDaysUntil('2026-05-11T13:00:00.000Z'); | ||
|
|
||
| expect(result).toBe(1); | ||
| }); | ||
|
|
||
| test('When the date is in the past, then it should clamp to 0', () => { | ||
| const result = getDaysUntil('2026-05-01T00:00:00.000Z'); | ||
|
|
||
| expect(result).toBe(0); | ||
| }); | ||
|
|
||
| test('When the date is exactly now, then it should return 0', () => { | ||
| const result = getDaysUntil('2026-05-11T12:00:00.000Z'); | ||
|
|
||
| expect(result).toBe(0); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| const MS_PER_DAY = 86_400_000; | ||
|
|
||
| export const getDaysUntil = (date: string | undefined): number | undefined => | ||
| date ? Math.max(0, Math.ceil((new Date(date).getTime() - Date.now()) / MS_PER_DAY)) : undefined; | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
Uh oh!
There was an error while loading. Please reload this page.