···
import 'package:coves_flutter/models/post.dart';
import 'package:coves_flutter/widgets/post_card.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import '../test_helpers/mock_providers.dart';
···
mockVoteProvider = MockVoteProvider();
-
Widget createTestWidget(FeedViewPost post) {
// ignore: argument_type_not_assignable
ChangeNotifierProvider<MockAuthProvider>.value(value: mockAuthProvider),
// ignore: argument_type_not_assignable
ChangeNotifierProvider<MockVoteProvider>.value(value: mockVoteProvider),
child: MaterialApp(home: Scaffold(body: PostCard(post: post))),
-
group('PostCard', skip: 'Provider type compatibility issues - needs mock refactoring', () {
-
testWidgets('renders all basic components', (tester) async {
-
final post = FeedViewPost(
-
uri: 'at://did:example/post/123',
-
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
-
community: CommunityRef(
-
did: 'did:plc:community',
-
name: 'test-community',
-
createdAt: DateTime(2024, 1, 1),
-
indexedAt: DateTime(2024, 1, 1),
-
text: 'Test post content',
-
title: 'Test Post Title',
-
await tester.pumpWidget(createTestWidget(post));
-
// Verify title is displayed
-
expect(find.text('Test Post Title'), findsOneWidget);
-
// Verify community name is displayed
-
expect(find.text('c/test-community'), findsOneWidget);
-
// Verify author handle is displayed
-
expect(find.text('@author.test'), findsOneWidget);
-
// Verify text content is displayed
-
expect(find.text('Test post content'), findsOneWidget);
-
// Verify stats are displayed
-
expect(find.text('8'), findsOneWidget); // score
-
expect(find.text('5'), findsOneWidget); // comment count
-
testWidgets('displays community avatar when available', (tester) async {
-
final post = FeedViewPost(
-
uri: 'at://did:example/post/123',
-
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
-
community: CommunityRef(
-
did: 'did:plc:community',
-
name: 'test-community',
-
avatar: 'https://example.com/avatar.jpg',
-
createdAt: DateTime(2024, 1, 1),
-
indexedAt: DateTime(2024, 1, 1),
-
stats: PostStats(upvotes: 0, downvotes: 0, score: 0, commentCount: 0),
-
await tester.pumpWidget(createTestWidget(post));
-
await tester.pumpAndSettle();
-
// Avatar image should be present
-
expect(find.byType(Image), findsWidgets);
-
testWidgets('shows fallback avatar when no avatar URL', (tester) async {
-
final post = FeedViewPost(
-
uri: 'at://did:example/post/123',
-
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
-
community: CommunityRef(
-
did: 'did:plc:community',
-
createdAt: DateTime(2024, 1, 1),
-
indexedAt: DateTime(2024, 1, 1),
-
stats: PostStats(upvotes: 0, downvotes: 0, score: 0, commentCount: 0),
-
await tester.pumpWidget(createTestWidget(post));
-
// Verify fallback shows first letter
-
expect(find.text('T'), findsOneWidget);
-
testWidgets('displays external link bar when embed present', (
-
final post = FeedViewPost(
-
uri: 'at://did:example/post/123',
-
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
-
community: CommunityRef(
-
did: 'did:plc:community',
-
name: 'test-community',
-
createdAt: DateTime(2024, 1, 1),
-
indexedAt: DateTime(2024, 1, 1),
-
stats: PostStats(upvotes: 0, downvotes: 0, score: 0, commentCount: 0),
-
type: 'social.coves.embed.external',
-
external: ExternalEmbed(
-
uri: 'https://example.com/article',
-
title: 'Example Article',
-
await tester.pumpWidget(createTestWidget(post));
-
// Verify external link bar is present
-
expect(find.text('example.com'), findsOneWidget);
-
expect(find.byIcon(Icons.open_in_new), findsOneWidget);
-
testWidgets('displays embed image when available', (tester) async {
-
final post = FeedViewPost(
-
uri: 'at://did:example/post/123',
-
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
-
community: CommunityRef(
-
did: 'did:plc:community',
-
name: 'test-community',
-
createdAt: DateTime(2024, 1, 1),
-
indexedAt: DateTime(2024, 1, 1),
-
stats: PostStats(upvotes: 0, downvotes: 0, score: 0, commentCount: 0),
-
type: 'social.coves.embed.external',
-
external: ExternalEmbed(
-
uri: 'https://example.com/article',
-
thumb: 'https://example.com/thumb.jpg',
-
await tester.pumpWidget(createTestWidget(post));
-
// Embed image should be loading/present
-
expect(find.byType(Image), findsWidgets);
-
testWidgets('renders without title', (tester) async {
-
final post = FeedViewPost(
-
uri: 'at://did:example/post/123',
-
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
-
community: CommunityRef(
-
did: 'did:plc:community',
-
name: 'test-community',
-
createdAt: DateTime(2024, 1, 1),
-
indexedAt: DateTime(2024, 1, 1),
-
text: 'Just body text',
-
stats: PostStats(upvotes: 0, downvotes: 0, score: 0, commentCount: 0),
-
await tester.pumpWidget(createTestWidget(post));
-
// Should render without errors
-
expect(find.text('Just body text'), findsOneWidget);
-
expect(find.text('c/test-community'), findsOneWidget);
-
testWidgets('has action buttons', (tester) async {
-
final post = FeedViewPost(
-
uri: 'at://did:example/post/123',
-
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
-
community: CommunityRef(
-
did: 'did:plc:community',
-
name: 'test-community',
-
createdAt: DateTime(2024, 1, 1),
-
indexedAt: DateTime(2024, 1, 1),
-
stats: PostStats(upvotes: 0, downvotes: 0, score: 0, commentCount: 0),
-
await tester.pumpWidget(createTestWidget(post));
-
// Verify action buttons are present
-
expect(find.byIcon(Icons.more_horiz), findsOneWidget); // menu
-
// Share, comment, and heart icons are custom widgets, verify by count
-
expect(find.byType(InkWell), findsWidgets);
···
import 'package:coves_flutter/models/post.dart';
+
import 'package:coves_flutter/services/streamable_service.dart';
import 'package:coves_flutter/widgets/post_card.dart';
+
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
+
import 'package:http_mock_adapter/http_mock_adapter.dart';
import 'package:provider/provider.dart';
import '../test_helpers/mock_providers.dart';
···
mockVoteProvider = MockVoteProvider();
+
Widget createTestWidget(
+
StreamableService? streamableService,
// ignore: argument_type_not_assignable
ChangeNotifierProvider<MockAuthProvider>.value(value: mockAuthProvider),
// ignore: argument_type_not_assignable
ChangeNotifierProvider<MockVoteProvider>.value(value: mockVoteProvider),
+
Provider<StreamableService>.value(
+
value: streamableService ?? StreamableService(),
child: MaterialApp(home: Scaffold(body: PostCard(post: post))),
+
skip: 'Provider type compatibility issues - needs mock refactoring',
+
testWidgets('renders all basic components', (tester) async {
+
final post = FeedViewPost(
+
uri: 'at://did:example/post/123',
+
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
+
community: CommunityRef(
+
did: 'did:plc:community',
+
name: 'test-community',
+
createdAt: DateTime(2024, 1, 1),
+
indexedAt: DateTime(2024, 1, 1),
+
text: 'Test post content',
+
title: 'Test Post Title',
+
await tester.pumpWidget(createTestWidget(post));
+
// Verify title is displayed
+
expect(find.text('Test Post Title'), findsOneWidget);
+
// Verify community name is displayed
+
expect(find.text('c/test-community'), findsOneWidget);
+
// Verify author handle is displayed
+
expect(find.text('@author.test'), findsOneWidget);
+
// Verify text content is displayed
+
expect(find.text('Test post content'), findsOneWidget);
+
// Verify stats are displayed
+
expect(find.text('8'), findsOneWidget); // score
+
expect(find.text('5'), findsOneWidget); // comment count
+
testWidgets('displays community avatar when available', (tester) async {
+
final post = FeedViewPost(
+
uri: 'at://did:example/post/123',
+
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
+
community: CommunityRef(
+
did: 'did:plc:community',
+
name: 'test-community',
+
avatar: 'https://example.com/avatar.jpg',
+
createdAt: DateTime(2024, 1, 1),
+
indexedAt: DateTime(2024, 1, 1),
+
await tester.pumpWidget(createTestWidget(post));
+
await tester.pumpAndSettle();
+
// Avatar image should be present
+
expect(find.byType(Image), findsWidgets);
+
testWidgets('shows fallback avatar when no avatar URL', (tester) async {
+
final post = FeedViewPost(
+
uri: 'at://did:example/post/123',
+
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
+
community: CommunityRef(
+
did: 'did:plc:community',
+
createdAt: DateTime(2024, 1, 1),
+
indexedAt: DateTime(2024, 1, 1),
+
await tester.pumpWidget(createTestWidget(post));
+
// Verify fallback shows first letter
+
expect(find.text('T'), findsOneWidget);
+
testWidgets('displays external link bar when embed present', (
+
final post = FeedViewPost(
+
uri: 'at://did:example/post/123',
+
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
+
community: CommunityRef(
+
did: 'did:plc:community',
+
name: 'test-community',
+
createdAt: DateTime(2024, 1, 1),
+
indexedAt: DateTime(2024, 1, 1),
+
type: 'social.coves.embed.external',
+
external: ExternalEmbed(
+
uri: 'https://example.com/article',
+
title: 'Example Article',
+
await tester.pumpWidget(createTestWidget(post));
+
// Verify external link bar is present
+
expect(find.text('example.com'), findsOneWidget);
+
expect(find.byIcon(Icons.open_in_new), findsOneWidget);
+
testWidgets('displays embed image when available', (tester) async {
+
final post = FeedViewPost(
+
uri: 'at://did:example/post/123',
+
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
+
community: CommunityRef(
+
did: 'did:plc:community',
+
name: 'test-community',
+
createdAt: DateTime(2024, 1, 1),
+
indexedAt: DateTime(2024, 1, 1),
+
type: 'social.coves.embed.external',
+
external: ExternalEmbed(
+
uri: 'https://example.com/article',
+
thumb: 'https://example.com/thumb.jpg',
+
await tester.pumpWidget(createTestWidget(post));
+
// Embed image should be loading/present
+
expect(find.byType(Image), findsWidgets);
+
testWidgets('renders without title', (tester) async {
+
final post = FeedViewPost(
+
uri: 'at://did:example/post/123',
+
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
+
community: CommunityRef(
+
did: 'did:plc:community',
+
name: 'test-community',
+
createdAt: DateTime(2024, 1, 1),
+
indexedAt: DateTime(2024, 1, 1),
+
text: 'Just body text',
+
await tester.pumpWidget(createTestWidget(post));
+
// Should render without errors
+
expect(find.text('Just body text'), findsOneWidget);
+
expect(find.text('c/test-community'), findsOneWidget);
+
testWidgets('has action buttons', (tester) async {
+
final post = FeedViewPost(
+
uri: 'at://did:example/post/123',
+
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
+
community: CommunityRef(
+
did: 'did:plc:community',
+
name: 'test-community',
+
createdAt: DateTime(2024, 1, 1),
+
indexedAt: DateTime(2024, 1, 1),
+
await tester.pumpWidget(createTestWidget(post));
+
// Verify action buttons are present
+
expect(find.byIcon(Icons.more_horiz), findsOneWidget); // menu
+
// Share, comment, and heart icons are custom widgets, verify by count
+
expect(find.byType(InkWell), findsWidgets);
+
testWidgets('displays play button overlay for Streamable videos', (
+
final post = FeedViewPost(
+
uri: 'at://did:example/post/123',
+
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
+
community: CommunityRef(
+
did: 'did:plc:community',
+
name: 'test-community',
+
createdAt: DateTime(2024, 1, 1),
+
indexedAt: DateTime(2024, 1, 1),
+
type: 'social.coves.embed.external',
+
external: ExternalEmbed(
+
uri: 'https://streamable.com/abc123',
+
thumb: 'https://example.com/thumb.jpg',
+
provider: 'streamable',
+
await tester.pumpWidget(createTestWidget(post));
+
// Verify play button is displayed
+
expect(find.byIcon(Icons.play_arrow), findsOneWidget);
+
'shows loading indicator when fetching video URL for Streamable',
+
final dio = Dio(BaseOptions(baseUrl: 'https://api.streamable.com'));
+
final dioAdapter = DioAdapter(dio: dio);
+
final streamableService = StreamableService(dio: dio);
+
// Delay the response to test loading state
+
(server) => server.reply(200, {
+
'mp4': {'url': '//cdn.streamable.com/video.mp4'},
+
}, delay: const Duration(milliseconds: 500)),
+
final post = FeedViewPost(
+
uri: 'at://did:example/post/123',
+
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
+
community: CommunityRef(
+
did: 'did:plc:community',
+
name: 'test-community',
+
createdAt: DateTime(2024, 1, 1),
+
indexedAt: DateTime(2024, 1, 1),
+
type: 'social.coves.embed.external',
+
external: ExternalEmbed(
+
uri: 'https://streamable.com/abc123',
+
thumb: 'https://example.com/thumb.jpg',
+
provider: 'streamable',
+
await tester.pumpWidget(
+
createTestWidget(post, streamableService: streamableService),
+
await tester.tap(find.byIcon(Icons.play_arrow));
+
// Verify loading indicator is displayed
+
expect(find.byType(CircularProgressIndicator), findsOneWidget);
+
testWidgets('does not show play button for non-video embeds', (
+
final post = FeedViewPost(
+
uri: 'at://did:example/post/123',
+
author: AuthorView(did: 'did:plc:author', handle: 'author.test'),
+
community: CommunityRef(
+
did: 'did:plc:community',
+
name: 'test-community',
+
createdAt: DateTime(2024, 1, 1),
+
indexedAt: DateTime(2024, 1, 1),
+
type: 'social.coves.embed.external',
+
external: ExternalEmbed(
+
uri: 'https://example.com/article',
+
thumb: 'https://example.com/thumb.jpg',
+
await tester.pumpWidget(createTestWidget(post));
+
// Verify play button is NOT displayed
+
expect(find.byIcon(Icons.play_arrow), findsNothing);