test kata lösung

This commit is contained in:
miqlangelo 2025-05-07 15:53:29 +02:00
parent 7a0835e62d
commit 125ea7443b
17 changed files with 4092 additions and 0 deletions

3
src/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"deno.enable": false
}

View File

@ -0,0 +1,7 @@
/** @type {import('ts-jest').JestConfigWithTsJest} **/
module.exports = {
testEnvironment: "node",
transform: {
"^.+\.tsx?$": ["ts-jest",{}],
}
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
{
"name": "12-testing-kata",
"version": "1.0.0",
"main": "index.js",
"type": "commonjs",
"scripts": {
"test": "jest"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"@types/jest": "^29.5.14",
"jest": "^29.7.0",
"ts-jest": "^29.3.2"
}
}

View File

@ -0,0 +1,15 @@
import { User } from '../types/index.ts';
export class ApiService {
fetchUser(id: number): Promise<User> {
return new Promise((resolve) =>
setTimeout(() => resolve({ id, username: 'Test User' }), 100)
);
}
fetchAllUsers(): Promise<User[]> {
return new Promise((resolve) =>
setTimeout(() => resolve([{ id: 1, username: 'User 1' }]), 100)
);
}
}

View File

@ -0,0 +1,16 @@
export class AuthService {
private loggedInUser: string | null = null;
login(username: string) {
if (!username) throw new Error('Username is required');
this.loggedInUser = username;
}
logout() {
this.loggedInUser = null;
}
isLoggedIn() {
return this.loggedInUser !== null;
}
}

View File

@ -0,0 +1,17 @@
import { User } from '../types/index.ts';
import { ApiService } from './ApiService.ts';
export class UserService {
constructor(private apiService: ApiService) {}
getUserById(id: number): Promise<User> {
if (!id) {
throw new Error('ID is required');
}
return this.apiService.fetchUser(id);
}
getAllUsers(): Promise<User[]> {
return this.apiService.fetchAllUsers();
}
}

View File

@ -0,0 +1,4 @@
export interface User {
id: number;
username: string;
}

View File

@ -0,0 +1,8 @@
export function sum(a: number, b: number): number {
return a + b;
}
export function divide(a: number, b: number): number {
if (b === 0) throw new Error('Division by zero');
return a / b;
}

View File

@ -0,0 +1,3 @@
export function isValidEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

View File

@ -0,0 +1,22 @@
import { beforeEach, describe, expect, test } from '@jest/globals';
import { ApiService } from '../src/services/ApiService';
describe('ApiService', () => {
let apiService: ApiService;
beforeEach(() => {
apiService = new ApiService();
});
test('fetchUser should return a user with given id', async () => {
const id = 42;
const user = await apiService.fetchUser(id);
expect(user).toEqual({ id, username: 'Test User' });
});
test('fetchAllUsers should return an array of users', async () => {
const users = await apiService.fetchAllUsers();
expect(users).toEqual([{ id: 1, username: 'User 1' }]);
expect(Array.isArray(users)).toBe(true);
expect(users.length).toBeGreaterThan(0);
});
});

View File

@ -0,0 +1,37 @@
import { beforeEach, describe, expect, test } from '@jest/globals';
import { AuthService } from '../src/services/AuthService';
describe('AuthService', () => {
let authService: AuthService;
beforeEach(() => {
authService = new AuthService();
});
test('login should set the logged-in user', () => {
authService.login('Alice');
expect(authService.isLoggedIn()).toBe(true);
});
test('login should throw an error if username is missing', () => {
expect(() => authService.login('')).toThrow('Username is required');
});
test('logout should clear the logged-in user', () => {
authService.login('Alice');
authService.logout();
expect(authService.isLoggedIn()).toBe(false);
});
test('isLoggedIn should return true if a user is logged in', () => {
authService.login('Alice');
expect(authService.isLoggedIn()).toBe(true);
});
test('isLoggedIn should return false if no user is logged in', () => {
expect(authService.isLoggedIn()).toBe(false);
});
});

View File

@ -0,0 +1,41 @@
import { beforeEach, describe, expect, jest, test } from '@jest/globals';
import { ApiService } from '../src/services/ApiService';
import { UserService } from '../src/services/UserService';
describe('UserService', () => {
let userService: UserService;
let apiService: jest.Mocked<ApiService>;
beforeEach(() => {
apiService = {
fetchUser: jest.fn(),
fetchAllUsers: jest.fn(),
};
userService = new UserService(apiService);
});
test('getUserById should return a user', async () => {
apiService.fetchUser.mockResolvedValue({ id: 1000, username: 'Test User' });
const user = await userService.getUserById(1000);
expect(user).toEqual({ id: 1000, username: 'Test User' });
expect(apiService.fetchUser).toHaveBeenCalledWith(1000);
});
test('getUserById should throw an error if ID is missing', () => {
const userService = new UserService(null as unknown as ApiService);
expect(() =>
userService.getUserById(undefined as unknown as number)
).toThrow('ID is required');
});
test('getAllUsers should return a list of users', async () => {
apiService.fetchAllUsers.mockResolvedValue([
{ id: 2000, username: 'User 1' },
]);
const users = await userService.getAllUsers();
expect(users).toEqual([{ id: 2000, username: 'User 1' }]);
expect(apiService.fetchAllUsers).toHaveBeenCalled();
});
});

View File

@ -0,0 +1,16 @@
import { describe, expect, test } from '@jest/globals';
import { divide, sum } from '../src/utils/math';
describe('math utils', () => {
test('sum should return the sum of two numbers', () => {
expect(sum(2, 3)).toBe(5);
});
test('divide should return the quotient of two numbers', () => {
expect(divide(10, 2)).toBe(5);
});
test('divide should throw an error when dividing by zero', () => {
expect(() => divide(10, 0)).toThrow('Division by zero');
});
});

View File

@ -0,0 +1,12 @@
import { describe, expect, test } from '@jest/globals';
import { isValidEmail } from '../src/utils/validation';
describe('validation utils', () => {
test('isValidEmail should return true for valid emails', () => {
expect(isValidEmail('test@example.com')).toBe(true);
});
test('isValidEmail should return false for invalid emails', () => {
expect(isValidEmail('invalid-email')).toBe(false);
});
});

View File

@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"noEmit": true,
"allowImportingTsExtensions": true
}
}