Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Fakes/Fakes/Products/ProductFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public enum ProductFactory {
/// Returns a fake product filled with data can be edited by the merchants
///
public static func productWithEditableDataFilled() -> Product {
Product.fake().copy(name: "name",
Product.fake().copy(productID: 123,
name: "name",
dateOnSaleStart: Date(),
dateOnSaleEnd: Date(),
fullDescription: "description",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,20 @@ extension EditableProductModel: ProductFormDataModel, TaxClassRequestable {
var existsRemotely: Bool {
product.existsRemotely
}

/// Helper to determine if a product model is empty.
/// We consider it as empty if its underlying product matches the `ProductFactory.createNewProduct` output.
/// Additionally we don't take dates into consideration as we don't control their value when creating a product.
///
func isEmpty() -> Bool {
guard let emptyProduct = ProductFactory().createNewProduct(type: productType, isVirtual: virtual, siteID: siteID) else {
return false
}

let commonDate = Date()
return emptyProduct.copy(date: commonDate, dateCreated: commonDate, dateModified: commonDate, dateOnSaleStart: commonDate, dateOnSaleEnd: commonDate) ==
product.copy(date: commonDate, dateCreated: commonDate, dateModified: commonDate, dateOnSaleStart: commonDate, dateOnSaleEnd: commonDate)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice idea!

}

extension EditableProductModel: Equatable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ final class ProductFormViewModel: ProductFormViewModelProtocol {
productOrVariationID: .product(id: product.productID),
isLocalID: !product.existsRemotely),
originalImages: originalProduct.images)
return hasProductChangesExcludingImages || hasImageChanges || password != originalPassword
return hasProductChangesExcludingImages || hasImageChanges || password != originalPassword || isNewTemplateProduct()
}
}

Expand Down Expand Up @@ -620,6 +620,15 @@ private extension ProductFormViewModel {

return controller
}

/// Helper to determine if the added/editted product comes as a new template product.
/// We assume that a new template product is a product that:
/// - Doesn't have an `id` - has not been saved remotely
/// - Is not empty.
///
private func isNewTemplateProduct() -> Bool {
originalProduct.productID == .zero && !originalProduct.isEmpty()
}
}

// MARK: Beta feature handling
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ extension ProductFormViewModelProtocol {
/// Returns `false` when it's a new blank product without any changes.
///
func shouldEnablePreviewButton() -> Bool {
!(formType == .add && !hasUnsavedChanges())
switch formType {
case .add:
return hasUnsavedChanges()
case .edit, .readonly:
return true
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ final class ProductFormViewModel_ObservablesTests: XCTestCase {

func testObservablesFromUpdatingProductPasswordRemotely() {
// Arrange
let product = Product.fake()
let product = Product.fake().copy(productID: 123)
let model = EditableProductModel(product: product)
let productImageActionHandler = ProductImageActionHandler(siteID: defaultSiteID, product: model)
let viewModel = ProductFormViewModel(product: model,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,11 +542,11 @@ final class ProductFormViewModelTests: XCTestCase {

// MARK: Preview button tests (with enabled Product Onboarding feature flag)

func test_disabled_preview_button_for_new_blank_product_without_any_changes() {
func test_disabled_preview_button_for_new_blank_product_without_any_changes() throws {
// Given
sessionManager.defaultSite = Site.fake().copy(frameNonce: "abc123")

let product = Product.fake().copy(statusKey: ProductStatus.published.rawValue)
let product = try XCTUnwrap(ProductFactory().createNewProduct(type: .simple, isVirtual: false, siteID: 123))
let viewModel = createViewModel(product: product,
formType: .add,
stores: stores,
Expand All @@ -560,6 +560,25 @@ final class ProductFormViewModelTests: XCTestCase {
XCTAssertFalse(viewModel.shouldEnablePreviewButton())
}

func test_enabled_preview_button_for_new_template_product() throws {
// Given
sessionManager.defaultSite = Site.fake().copy(frameNonce: "abc123")

// Adding some value to simulate a template product
let product = try XCTUnwrap(ProductFactory().createNewProduct(type: .simple, isVirtual: false, siteID: 123)?.copy(price: "10.00"))
let viewModel = createViewModel(product: product,
formType: .add,
stores: stores,
featureFlagService: MockFeatureFlagService(isProductsOnboardingEnabled: true))

// When
let actionButtons = viewModel.actionButtons

// Then
XCTAssertEqual(actionButtons, [.preview, .publish, .more])
XCTAssertTrue(viewModel.shouldEnablePreviewButton())
}

func test_enabled_preview_button_for_new_product_with_pending_changes() {
// Given
sessionManager.defaultSite = Site.fake().copy(frameNonce: "abc123")
Expand Down