Add unit tests for models and services
- Implemented unit tests for the Package model, covering methods such as generateId, findById, findByName, and version management. - Created unit tests for the Repository model, including repository creation, name validation, and retrieval methods. - Added tests for the Session model, focusing on session creation, validation, and invalidation. - Developed unit tests for the User model, ensuring user creation, password hashing, and retrieval methods function correctly. - Implemented AuthService tests, validating login, token refresh, and session management. - Added TokenService tests, covering token creation, validation, and revocation processes.
This commit is contained in:
228
test/integration/organization.test.ts
Normal file
228
test/integration/organization.test.ts
Normal file
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Organization integration tests
|
||||
* Tests organization CRUD and member management through the API
|
||||
*/
|
||||
|
||||
import { assertEquals, assertExists } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import {
|
||||
setupTestDb,
|
||||
teardownTestDb,
|
||||
cleanupTestDb,
|
||||
createTestUser,
|
||||
loginUser,
|
||||
post,
|
||||
get,
|
||||
put,
|
||||
del,
|
||||
assertStatus,
|
||||
createAuthHeader,
|
||||
} from '../helpers/index.ts';
|
||||
|
||||
describe('Organization API Integration', () => {
|
||||
let accessToken: string;
|
||||
let testUserId: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
await setupTestDb();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await teardownTestDb();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await cleanupTestDb();
|
||||
const { user, password } = await createTestUser({ status: 'active' });
|
||||
testUserId = user.id;
|
||||
const tokens = await loginUser(user.email, password);
|
||||
accessToken = tokens.accessToken;
|
||||
});
|
||||
|
||||
describe('POST /api/v1/organizations', () => {
|
||||
it('should create organization', async () => {
|
||||
const response = await post(
|
||||
'/api/v1/organizations',
|
||||
{
|
||||
name: 'my-org',
|
||||
displayName: 'My Organization',
|
||||
description: 'A test organization',
|
||||
},
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
assertStatus(response, 201);
|
||||
const body = response.body as Record<string, unknown>;
|
||||
assertEquals(body.name, 'my-org');
|
||||
assertEquals(body.displayName, 'My Organization');
|
||||
});
|
||||
|
||||
it('should create organization with dots in name', async () => {
|
||||
const response = await post(
|
||||
'/api/v1/organizations',
|
||||
{
|
||||
name: 'push.rocks',
|
||||
displayName: 'Push Rocks',
|
||||
},
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
assertStatus(response, 201);
|
||||
const body = response.body as Record<string, unknown>;
|
||||
assertEquals(body.name, 'push.rocks');
|
||||
});
|
||||
|
||||
it('should reject duplicate org name', async () => {
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'duplicate', displayName: 'First' },
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
const response = await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'duplicate', displayName: 'Second' },
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
assertStatus(response, 409);
|
||||
});
|
||||
|
||||
it('should reject invalid org name', async () => {
|
||||
const response = await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: '.invalid', displayName: 'Invalid' },
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
assertStatus(response, 400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /api/v1/organizations', () => {
|
||||
it('should list user organizations', async () => {
|
||||
// Create some organizations
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'org1', displayName: 'Org 1' },
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'org2', displayName: 'Org 2' },
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
const response = await get('/api/v1/organizations', createAuthHeader(accessToken));
|
||||
|
||||
assertStatus(response, 200);
|
||||
const body = response.body as Record<string, unknown>[];
|
||||
assertEquals(body.length >= 2, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /api/v1/organizations/:orgName', () => {
|
||||
it('should get organization by name', async () => {
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'get-me', displayName: 'Get Me' },
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
const response = await get('/api/v1/organizations/get-me', createAuthHeader(accessToken));
|
||||
|
||||
assertStatus(response, 200);
|
||||
const body = response.body as Record<string, unknown>;
|
||||
assertEquals(body.name, 'get-me');
|
||||
});
|
||||
|
||||
it('should return 404 for non-existent org', async () => {
|
||||
const response = await get(
|
||||
'/api/v1/organizations/non-existent',
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
assertStatus(response, 404);
|
||||
});
|
||||
});
|
||||
|
||||
describe('PUT /api/v1/organizations/:orgName', () => {
|
||||
it('should update organization', async () => {
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'update-me', displayName: 'Original' },
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
const response = await put(
|
||||
'/api/v1/organizations/update-me',
|
||||
{ displayName: 'Updated', description: 'New description' },
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
assertStatus(response, 200);
|
||||
const body = response.body as Record<string, unknown>;
|
||||
assertEquals(body.displayName, 'Updated');
|
||||
assertEquals(body.description, 'New description');
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE /api/v1/organizations/:orgName', () => {
|
||||
it('should delete organization', async () => {
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'delete-me', displayName: 'Delete Me' },
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
const response = await del('/api/v1/organizations/delete-me', createAuthHeader(accessToken));
|
||||
|
||||
assertStatus(response, 200);
|
||||
|
||||
// Verify deleted
|
||||
const getResponse = await get(
|
||||
'/api/v1/organizations/delete-me',
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
assertStatus(getResponse, 404);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Organization Members', () => {
|
||||
it('should list organization members', async () => {
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'members-org', displayName: 'Members Org' },
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
const response = await get(
|
||||
'/api/v1/organizations/members-org/members',
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
assertStatus(response, 200);
|
||||
const body = response.body as Record<string, unknown>[];
|
||||
assertEquals(body.length >= 1, true); // At least the creator
|
||||
});
|
||||
|
||||
it('should add member to organization', async () => {
|
||||
// Create another user
|
||||
const { user: newUser } = await createTestUser({ email: 'newmember@example.com' });
|
||||
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'add-member-org', displayName: 'Add Member Org' },
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
const response = await post(
|
||||
'/api/v1/organizations/add-member-org/members',
|
||||
{ userId: newUser.id, role: 'member' },
|
||||
createAuthHeader(accessToken)
|
||||
);
|
||||
|
||||
assertStatus(response, 201);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user