fix(feature_wordpress): allow pending review products to move to draft
Publish Docs / publish-docs (push) Successful in 1m12s
Details
Publish Docs / publish-docs (push) Successful in 1m12s
Details
This commit is contained in:
parent
f9c5ef36da
commit
f8f373b018
|
|
@ -103,14 +103,7 @@ class FakeProductPublishingRepository implements ProductPublishingRepository {
|
|||
}
|
||||
|
||||
final original = _drafts[index];
|
||||
final updated = ProductDraft(
|
||||
id: original.id,
|
||||
name: original.name,
|
||||
description: original.description,
|
||||
price: original.price,
|
||||
sku: original.sku,
|
||||
category: original.category,
|
||||
imageUrl: original.imageUrl,
|
||||
final updated = original.copyWith(
|
||||
status: PublishStatus.published,
|
||||
lastModified: DateTime.now(),
|
||||
);
|
||||
|
|
@ -128,14 +121,7 @@ class FakeProductPublishingRepository implements ProductPublishingRepository {
|
|||
}
|
||||
|
||||
final original = _drafts[index];
|
||||
final updated = ProductDraft(
|
||||
id: original.id,
|
||||
name: original.name,
|
||||
description: original.description,
|
||||
price: original.price,
|
||||
sku: original.sku,
|
||||
category: original.category,
|
||||
imageUrl: original.imageUrl,
|
||||
final updated = original.copyWith(
|
||||
status: status,
|
||||
lastModified: DateTime.now(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -23,4 +23,29 @@ class ProductDraft {
|
|||
required this.status,
|
||||
required this.lastModified,
|
||||
});
|
||||
|
||||
/// Returns a copy of this [ProductDraft] with the given fields replaced.
|
||||
ProductDraft copyWith({
|
||||
String? id,
|
||||
String? name,
|
||||
String? description,
|
||||
double? price,
|
||||
String? sku,
|
||||
String? category,
|
||||
String? imageUrl,
|
||||
PublishStatus? status,
|
||||
DateTime? lastModified,
|
||||
}) {
|
||||
return ProductDraft(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
description: description ?? this.description,
|
||||
price: price ?? this.price,
|
||||
sku: sku ?? this.sku,
|
||||
category: category ?? this.category,
|
||||
imageUrl: imageUrl ?? this.imageUrl,
|
||||
status: status ?? this.status,
|
||||
lastModified: lastModified ?? this.lastModified,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import 'publish_status_chip.dart';
|
|||
/// Includes product image placeholder, description, metadata, and
|
||||
/// status-aware action buttons:
|
||||
/// - **Publish to Store** when the draft status is [PublishStatus.draft].
|
||||
/// - **Move to Draft** when the draft status is [PublishStatus.published].
|
||||
/// - No action button for other statuses.
|
||||
/// - **Move to Draft** when the draft status is [PublishStatus.published],
|
||||
/// [PublishStatus.unpublished], or [PublishStatus.pendingReview].
|
||||
class ProductPreviewPanel extends StatelessWidget {
|
||||
final ProductDraft draft;
|
||||
final VoidCallback? onPublish;
|
||||
|
|
@ -118,7 +118,9 @@ class ProductPreviewPanel extends StatelessWidget {
|
|||
label: const Text('Publish to Store'),
|
||||
),
|
||||
),
|
||||
if (draft.status == PublishStatus.published)
|
||||
if (draft.status == PublishStatus.published ||
|
||||
draft.status == PublishStatus.unpublished ||
|
||||
draft.status == PublishStatus.pendingReview)
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: OutlinedButton.icon(
|
||||
|
|
|
|||
|
|
@ -75,6 +75,20 @@ void main() {
|
|||
expect(product1.status, PublishStatus.draft);
|
||||
});
|
||||
|
||||
test('unpublished to draft updates only the target product', () async {
|
||||
// Product 6 starts as unpublished.
|
||||
final updated = await repository.updateProductStatus('6', PublishStatus.draft);
|
||||
|
||||
expect(updated.id, '6');
|
||||
expect(updated.status, PublishStatus.draft);
|
||||
expect(updated.name, 'Sublimated Slate Coaster');
|
||||
|
||||
// Verify the change is persisted in the list.
|
||||
final drafts = await repository.getProductDrafts();
|
||||
final product6 = drafts.firstWhere((d) => d.id == '6');
|
||||
expect(product6.status, PublishStatus.draft);
|
||||
});
|
||||
|
||||
test('preserves other products unchanged', () async {
|
||||
final draftsBefore = await repository.getProductDrafts();
|
||||
|
||||
|
|
|
|||
|
|
@ -157,6 +157,30 @@ void main() {
|
|||
expect(controller.updatingIds, isEmpty);
|
||||
});
|
||||
|
||||
test('pendingReview to draft updates status and reloads', () async {
|
||||
await controller.load();
|
||||
|
||||
// Product 3 starts as pendingReview.
|
||||
await controller.updateStatus('3', PublishStatus.draft);
|
||||
|
||||
final updated = controller.drafts.firstWhere((d) => d.id == '3');
|
||||
expect(updated.status, PublishStatus.draft);
|
||||
expect(controller.error, isNull);
|
||||
expect(controller.updatingIds, isEmpty);
|
||||
});
|
||||
|
||||
test('unpublished to draft updates status and reloads', () async {
|
||||
await controller.load();
|
||||
|
||||
// Product 6 starts as unpublished.
|
||||
await controller.updateStatus('6', PublishStatus.draft);
|
||||
|
||||
final updated = controller.drafts.firstWhere((d) => d.id == '6');
|
||||
expect(updated.status, PublishStatus.draft);
|
||||
expect(controller.error, isNull);
|
||||
expect(controller.updatingIds, isEmpty);
|
||||
});
|
||||
|
||||
test('sets error on failed update', () async {
|
||||
await controller.load();
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,18 @@ void main() {
|
|||
lastModified: DateTime(2026, 4, 1),
|
||||
);
|
||||
|
||||
final unpublishedDraft = ProductDraft(
|
||||
id: '4',
|
||||
name: 'Unpublished Product',
|
||||
description: 'Previously published but taken down.',
|
||||
price: 9.99,
|
||||
sku: 'UP-001',
|
||||
category: 'Coasters',
|
||||
imageUrl: '',
|
||||
status: PublishStatus.unpublished,
|
||||
lastModified: DateTime(2026, 3, 20),
|
||||
);
|
||||
|
||||
Widget buildTestWidget(
|
||||
ProductDraft draft, {
|
||||
VoidCallback? onPublish,
|
||||
|
|
@ -110,10 +122,21 @@ void main() {
|
|||
expect(find.text('Publish to Store'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('pending review row shows no action button', (tester) async {
|
||||
testWidgets('pending review row shows Move to Draft button', (tester) async {
|
||||
await tester.pumpWidget(buildTestWidget(pendingDraft));
|
||||
expect(find.text('Move to Draft'), findsOneWidget);
|
||||
expect(find.text('Publish to Store'), findsNothing);
|
||||
expect(find.text('Move to Draft'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('calls onMoveToDraft when Move to Draft is tapped for pending review', (
|
||||
tester,
|
||||
) async {
|
||||
var movedToDraft = false;
|
||||
await tester.pumpWidget(
|
||||
buildTestWidget(pendingDraft, onMoveToDraft: () => movedToDraft = true),
|
||||
);
|
||||
await tester.tap(find.text('Move to Draft'));
|
||||
expect(movedToDraft, true);
|
||||
});
|
||||
|
||||
testWidgets('calls onMoveToDraft when Move to Draft is tapped', (tester) async {
|
||||
|
|
@ -124,6 +147,21 @@ void main() {
|
|||
await tester.tap(find.text('Move to Draft'));
|
||||
expect(movedToDraft, true);
|
||||
});
|
||||
|
||||
testWidgets('unpublished row shows Move to Draft button', (tester) async {
|
||||
await tester.pumpWidget(buildTestWidget(unpublishedDraft));
|
||||
expect(find.text('Move to Draft'), findsOneWidget);
|
||||
expect(find.text('Publish to Store'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('calls onMoveToDraft when Move to Draft is tapped for unpublished', (tester) async {
|
||||
var movedToDraft = false;
|
||||
await tester.pumpWidget(
|
||||
buildTestWidget(unpublishedDraft, onMoveToDraft: () => movedToDraft = true),
|
||||
);
|
||||
await tester.tap(find.text('Move to Draft'));
|
||||
expect(movedToDraft, true);
|
||||
});
|
||||
});
|
||||
|
||||
group('updating state', () {
|
||||
|
|
@ -151,6 +189,30 @@ void main() {
|
|||
expect(tapped, false);
|
||||
});
|
||||
|
||||
testWidgets('Move to Draft button is disabled while updating for pending review', (
|
||||
tester,
|
||||
) async {
|
||||
var tapped = false;
|
||||
await tester.pumpWidget(
|
||||
buildTestWidget(pendingDraft, isUpdating: true, onMoveToDraft: () => tapped = true),
|
||||
);
|
||||
|
||||
expect(find.text('Move to Draft'), findsOneWidget);
|
||||
await tester.tap(find.text('Move to Draft'));
|
||||
expect(tapped, false);
|
||||
});
|
||||
|
||||
testWidgets('Move to Draft button is disabled while updating for unpublished', (tester) async {
|
||||
var tapped = false;
|
||||
await tester.pumpWidget(
|
||||
buildTestWidget(unpublishedDraft, isUpdating: true, onMoveToDraft: () => tapped = true),
|
||||
);
|
||||
|
||||
expect(find.text('Move to Draft'), findsOneWidget);
|
||||
await tester.tap(find.text('Move to Draft'));
|
||||
expect(tapped, false);
|
||||
});
|
||||
|
||||
testWidgets('shows progress indicator while updating', (tester) async {
|
||||
await tester.pumpWidget(buildTestWidget(sampleDraft, isUpdating: true));
|
||||
expect(find.byType(CircularProgressIndicator), findsOneWidget);
|
||||
|
|
|
|||
Loading…
Reference in New Issue