Files
social-app/apps/test/features/todo/quadrant_drag_test.dart
T

177 lines
5.2 KiB
Dart

import 'package:dio/dio.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:social_app/features/todo/data/todo_api.dart';
import 'package:social_app/core/api/i_api_client.dart';
class MockApiClient extends Mock implements IApiClient {}
class FakeRequestOptions extends Fake implements RequestOptions {}
void main() {
late TodoApi todoApi;
late MockApiClient mockClient;
setUpAll(() {
registerFallbackValue(FakeRequestOptions());
});
setUp(() {
mockClient = MockApiClient();
todoApi = TodoApi(mockClient);
});
group('TodoApi.updateTodo - cross-quadrant drag', () {
test(
'calls PATCH with priority when moving to different quadrant',
() async {
const todoId = 'todo-123';
const targetPriority = 2;
const targetOrder = 0;
when(
() => mockClient.patch(any(), data: any(named: 'data')),
).thenAnswer(
(_) async => Response(
requestOptions: RequestOptions(path: '/api/v1/todos/$todoId'),
data: {
'id': todoId,
'owner_id': 'user-1',
'title': 'Test Todo',
'priority': targetPriority,
'order': targetOrder,
'status': 'pending',
'created_at': '2024-01-01T00:00:00Z',
'updated_at': '2024-01-01T00:00:00Z',
},
),
);
final result = await todoApi.updateTodo(
todoId,
priority: targetPriority,
order: targetOrder,
);
expect(result.priority, targetPriority);
expect(result.order, targetOrder);
verify(
() => mockClient.patch(
'/api/v1/todos/$todoId',
data: {'priority': targetPriority, 'order': targetOrder},
),
).called(1);
},
);
test('throws when API fails - triggers rollback', () async {
const todoId = 'todo-123';
when(
() => mockClient.patch(any(), data: any(named: 'data')),
).thenThrow(Exception('Network error'));
expect(
() => todoApi.updateTodo(todoId, priority: 2, order: 0),
throwsException,
);
});
});
group('Quadrant priority mapping', () {
test('priority 1 = important urgent (Q1)', () async {
when(() => mockClient.patch(any(), data: any(named: 'data'))).thenAnswer(
(_) async => Response(
requestOptions: RequestOptions(path: '/api/v1/todos/todo-1'),
data: {
'id': 'todo-1',
'owner_id': 'user-1',
'title': 'Q1 Todo',
'priority': 1,
'order': 1,
'status': 'pending',
'created_at': '2024-01-01T00:00:00Z',
'updated_at': '2024-01-01T00:00:00Z',
},
),
);
final result = await todoApi.updateTodo('todo-1', priority: 1, order: 1);
expect(result.priority, 1);
expect(result.order, 1);
});
test('priority 2 = important not urgent (Q3)', () async {
when(() => mockClient.patch(any(), data: any(named: 'data'))).thenAnswer(
(_) async => Response(
requestOptions: RequestOptions(path: '/api/v1/todos/todo-2'),
data: {
'id': 'todo-2',
'owner_id': 'user-1',
'title': 'Q3 Todo',
'priority': 2,
'order': 2,
'status': 'pending',
'created_at': '2024-01-01T00:00:00Z',
'updated_at': '2024-01-01T00:00:00Z',
},
),
);
final result = await todoApi.updateTodo('todo-2', priority: 2, order: 2);
expect(result.priority, 2);
expect(result.order, 2);
});
test('priority 3 = urgent not important (Q2)', () async {
when(() => mockClient.patch(any(), data: any(named: 'data'))).thenAnswer(
(_) async => Response(
requestOptions: RequestOptions(path: '/api/v1/todos/todo-3'),
data: {
'id': 'todo-3',
'owner_id': 'user-1',
'title': 'Q2 Todo',
'priority': 3,
'order': 0,
'status': 'pending',
'created_at': '2024-01-01T00:00:00Z',
'updated_at': '2024-01-01T00:00:00Z',
},
),
);
final result = await todoApi.updateTodo('todo-3', priority: 3, order: 0);
expect(result.priority, 3);
expect(result.order, 0);
});
});
group('TodoApi.reorderTodos', () {
test('calls batch reorder endpoint once', () async {
when(() => mockClient.patch(any(), data: any(named: 'data'))).thenAnswer(
(_) async => Response(
requestOptions: RequestOptions(path: '/api/v1/todos/reorder'),
data: {},
),
);
await todoApi.reorderTodos(const [
TodoReorderItemPayload(id: 'todo-1', priority: 1, order: 0),
TodoReorderItemPayload(id: 'todo-2', priority: 1, order: 1),
]);
verify(
() => mockClient.patch(
'/api/v1/todos/reorder',
data: {
'items': [
{'id': 'todo-1', 'priority': 1, 'order': 0},
{'id': 'todo-2', 'priority': 1, 'order': 1},
],
},
),
).called(1);
});
});
}