-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tests: update tests and use msw for api mocks
- Loading branch information
1 parent
7449f5f
commit 90ccd57
Showing
11 changed files
with
396 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,85 +1,111 @@ | ||
import { describe, expect, it, vi } from 'vitest' | ||
import { afterAll, afterEach, beforeAll, expect } from 'vitest' | ||
|
||
import { setupServer } from 'msw/node' | ||
import { http, HttpResponse } from 'msw' | ||
import { loginWithEmailAndPassword, loginWithOtp, loginWithToken } from './actions' | ||
import { ofetch } from 'ofetch' | ||
import chalk from 'chalk' | ||
|
||
vi.mock('ofetch', () => ({ | ||
ofetch: vi.fn(), | ||
})) | ||
const emailRegex = /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/ | ||
|
||
describe('login actions', () => { | ||
beforeEach(() => { | ||
vi.clearAllMocks() | ||
}) | ||
const handlers = [ | ||
http.get('https://api.storyblok.com/v1/users/me', async ({ request }) => { | ||
const token = request.headers.get('Authorization') | ||
if (token === 'valid-token') { return HttpResponse.json({ data: 'user data' }) } | ||
return new HttpResponse('Unauthorized', { status: 401 }) | ||
}), | ||
http.post('https://api.storyblok.com/v1/users/login', async ({ request }) => { | ||
const body = await request.json() as { email: string, password: string } | ||
|
||
if (!emailRegex.test(body.email)) { | ||
return new HttpResponse('Unprocessable Entity', { status: 422 }) | ||
} | ||
|
||
if (body?.email === '[email protected]' && body?.password === 'password') { | ||
return HttpResponse.json({ otp_required: true }) | ||
} | ||
else { | ||
return new HttpResponse('Unauthorized', { status: 401 }) | ||
} | ||
}), | ||
] | ||
|
||
const server = setupServer(...handlers) | ||
|
||
// Start server before all tests | ||
beforeAll(() => server.listen({ onUnhandledRequest: 'error' })) | ||
|
||
// Close server after all tests | ||
afterAll(() => server.close()) | ||
|
||
// Reset handlers after each test `important for test isolation` | ||
afterEach(() => server.resetHandlers()) | ||
|
||
describe('login actions', () => { | ||
describe('loginWithToken', () => { | ||
it('should login successfully with a valid token', async () => { | ||
const mockResponse = { data: 'user data' } | ||
vi.mocked(ofetch).mockResolvedValue(mockResponse) | ||
|
||
const result = await loginWithToken('valid-token', 'eu') | ||
expect(result).toEqual(mockResponse) | ||
}) | ||
|
||
it('should throw an masked error for invalid token', async () => { | ||
const mockError = { | ||
response: { status: 401 }, | ||
data: { error: 'Unauthorized' }, | ||
} | ||
vi.mocked(ofetch).mockRejectedValue(mockError) | ||
|
||
await expect(loginWithToken('invalid-token', 'eu')).rejects.toThrow( | ||
new Error(`The token provided ${chalk.bold('inva*********')} is invalid: ${chalk.bold('401 Unauthorized')} | ||
Please make sure you are using the correct token and try again.`), | ||
new Error(`The token provided ${chalk.bold('inva*********')} is invalid. | ||
Please make sure you are using the correct token and try again.`), | ||
) | ||
}) | ||
|
||
it('should throw a network error if response is empty (network)', async () => { | ||
const mockError = new Error('Network error') | ||
vi.mocked(ofetch).mockRejectedValue(mockError) | ||
|
||
server.use( | ||
http.get('https://api.storyblok.com/v1/users/me', () => { | ||
return new HttpResponse(null, { status: 500 }) | ||
}), | ||
) | ||
await expect(loginWithToken('any-token', 'eu')).rejects.toThrow( | ||
'No response from server, please check if you are correctly connected to internet', | ||
) | ||
}) | ||
}) | ||
|
||
describe('loginWithEmailAndPassword', () => { | ||
it('should login successfully with valid email and password', async () => { | ||
const mockResponse = { data: 'user data' } | ||
vi.mocked(ofetch).mockResolvedValue(mockResponse) | ||
|
||
const result = await loginWithEmailAndPassword('[email protected]', 'password', 'eu') | ||
expect(result).toEqual(mockResponse) | ||
it('should get if the user requires otp', async () => { | ||
const expected = { otp_required: true } | ||
const result = await loginWithEmailAndPassword('[email protected]', 'password', 'eu') | ||
expect(result).toEqual(expected) | ||
}) | ||
|
||
it('should throw a generic error for login failure', async () => { | ||
const mockError = new Error('Network error') | ||
vi.mocked(ofetch).mockRejectedValue(mockError) | ||
it('should throw an error for invalid email', async () => { | ||
await expect(loginWithEmailAndPassword('invalid-email', 'password', 'eu')).rejects.toThrow( | ||
'The provided credentials are invalid', | ||
) | ||
}) | ||
|
||
await expect(loginWithEmailAndPassword('[email protected]', 'password', 'eu')).rejects.toThrow( | ||
'Error logging in with email and password', | ||
it('should throw an error for invalid credentials', async () => { | ||
await expect(loginWithEmailAndPassword('[email protected]', 'password', 'eu')).rejects.toThrow( | ||
'The user is not authorized to access the API', | ||
) | ||
}) | ||
}) | ||
|
||
describe('loginWithOtp', () => { | ||
it('should login successfully with valid email, password, and otp', async () => { | ||
const mockResponse = { data: 'user data' } | ||
vi.mocked(ofetch).mockResolvedValue(mockResponse) | ||
|
||
const result = await loginWithOtp('[email protected]', 'password', '123456', 'eu') | ||
expect(result).toEqual(mockResponse) | ||
}) | ||
server.use( | ||
http.post('https://api.storyblok.com/v1/users/login', async ({ request }) => { | ||
const body = await request.json() as { email: string, password: string, otp_attempt: string } | ||
if (body?.email === '[email protected]' && body?.password === 'password' && body?.otp_attempt === '123456') { | ||
return HttpResponse.json({ access_token: 'Awiwi' }) | ||
} | ||
|
||
else { | ||
return new HttpResponse('Unauthorized', { status: 401 }) | ||
} | ||
}), | ||
) | ||
const expected = { access_token: 'Awiwi' } | ||
|
||
it('should throw a generic error for login failure', async () => { | ||
const mockError = new Error('Network error') | ||
vi.mocked(ofetch).mockRejectedValue(mockError) | ||
const result = await loginWithOtp('[email protected]', 'password', '123456', 'eu') | ||
|
||
await expect(loginWithOtp('[email protected]', 'password', '123456', 'eu')).rejects.toThrow( | ||
'Error logging in with email, password and otp', | ||
) | ||
expect(result).toEqual(expected) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.