Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,28 @@
import { getRecommendedDocumentFields } from '../recommended-document-fields';
import { RecommendedDocument } from '../types';

declare const global: {
wcpaySettings: {
featureFlags: {
isDisputeAdditionalEvidenceTypesEnabled: boolean;
};
};
};

describe( 'Recommended Documents', () => {
const originalWcpaySettings = global.wcpaySettings;

beforeEach( () => {
global.wcpaySettings = {
featureFlags: {
isDisputeAdditionalEvidenceTypesEnabled: false,
},
};
} );

afterEach( () => {
global.wcpaySettings = originalWcpaySettings;
} );
describe( 'getRecommendedDocumentFields', () => {
it( 'should return default fields when no specific reason is provided', () => {
const result = getRecommendedDocumentFields( '' );
Expand Down Expand Up @@ -47,14 +68,15 @@ describe( 'Recommended Documents', () => {
} );

it( 'should return fields for subscription_canceled reason', () => {
// When feature flag is OFF, uses fallback fields.
const result = getRecommendedDocumentFields(
'subscription_canceled'
);
expect( result ).toHaveLength( 6 ); // Default fields + 3 specific fields
expect( result[ 0 ].key ).toBe( 'receipt' );
expect( result[ 1 ].key ).toBe( 'customer_communication' );
expect( result[ 2 ].key ).toBe( 'access_activity_log' );
expect( result[ 2 ].label ).toBe( 'Subscription logs' );
expect( result[ 2 ].label ).toBe( 'Proof of active subscription' );
expect( result[ 3 ].key ).toBe( 'refund_policy' );
expect( result[ 4 ].key ).toBe( 'cancellation_policy' );
expect( result[ 5 ].key ).toBe( 'uncategorized_file' );
Expand Down Expand Up @@ -140,6 +162,9 @@ describe( 'Recommended Documents', () => {
} );

it( 'should return fields for duplicate reason with is_duplicate status', () => {
// Duplicate-specific fields require the feature flag to be enabled
global.wcpaySettings.featureFlags.isDisputeAdditionalEvidenceTypesEnabled = true;

const fields = getRecommendedDocumentFields(
'duplicate',
undefined,
Expand All @@ -158,6 +183,9 @@ describe( 'Recommended Documents', () => {
} );

it( 'should return fields for duplicate reason with is_not_duplicate status', () => {
// Duplicate-specific fields require the feature flag to be enabled
global.wcpaySettings.featureFlags.isDisputeAdditionalEvidenceTypesEnabled = true;

const fields = getRecommendedDocumentFields(
'duplicate',
undefined,
Expand All @@ -174,27 +202,39 @@ describe( 'Recommended Documents', () => {
expect( fields[ 3 ].key ).toBe( 'refund_policy' );
expect( fields[ 3 ].label ).toBe( 'Refund policy' );
expect( fields[ 3 ].description ).toBe(
'A screenshot of the refund policy for the provided service.'
"A screenshot of your store's refund policy."
);
expect( fields[ 4 ].key ).toBe( 'uncategorized_file' );
} );

it( 'should return fields for duplicate reason with missing duplicate status', () => {
const fields = getRecommendedDocumentFields( 'duplicate' );
expect( fields ).toHaveLength( 5 );
expect( fields[ 0 ].key ).toBe( 'receipt' );
expect( fields[ 1 ].key ).toBe( 'duplicate_charge_documentation' );
expect( fields[ 1 ].label ).toBe( 'Any additional receipts' );
expect( fields[ 1 ].description ).toBe(
'Receipt(s) for any other order(s) from this customer.'
it( 'should return fallback fields for duplicate + is_duplicate when feature flag is disabled', () => {
const fields = getRecommendedDocumentFields(
'duplicate',
undefined,
'is_duplicate'
);
expect( fields[ 2 ].key ).toBe( 'customer_communication' );
expect( fields ).toHaveLength( 6 );
expect( fields[ 0 ].key ).toBe( 'receipt' );
expect( fields[ 1 ].key ).toBe( 'customer_communication' );
expect( fields[ 2 ].key ).toBe( 'access_activity_log' );
expect( fields[ 2 ].label ).toBe( 'Proof of active subscription' );
expect( fields[ 3 ].key ).toBe( 'refund_policy' );
expect( fields[ 3 ].label ).toBe( 'Refund policy' );
expect( fields[ 3 ].description ).toBe(
'A screenshot of the refund policy for the provided service.'
expect( fields[ 4 ].key ).toBe( 'cancellation_policy' );
expect( fields[ 5 ].key ).toBe( 'uncategorized_file' );
} );

it( 'should return fallback fields for duplicate + is_not_duplicate when feature flag is disabled', () => {
const fields = getRecommendedDocumentFields(
'duplicate',
undefined,
'is_not_duplicate'
);
expect( fields[ 4 ].key ).toBe( 'uncategorized_file' );
expect( fields ).toHaveLength( 4 );
expect( fields[ 0 ].key ).toBe( 'receipt' );
expect( fields[ 1 ].key ).toBe( 'customer_communication' );
expect( fields[ 2 ].key ).toBe( 'refund_policy' );
expect( fields[ 2 ].label ).toBe( 'Store refund policy' );
expect( fields[ 3 ].key ).toBe( 'uncategorized_file' );
} );

it( 'should maintain correct order of fields', () => {
Expand All @@ -214,47 +254,87 @@ describe( 'Recommended Documents', () => {
] );
} );

describe( 'subscription_canceled with productType variations', () => {
it( 'should return fields with subscription logs for subscription_canceled with single product type', () => {
describe( 'evidence matrix with feature flag', () => {
it( 'should return matrix fields for fraudulent + booking_reservation when feature flag is enabled', () => {
global.wcpaySettings.featureFlags.isDisputeAdditionalEvidenceTypesEnabled = true;

const result = getRecommendedDocumentFields(
'subscription_canceled',
'fraudulent',
undefined,
undefined,
'physical_product'
'booking_reservation'
);

expect( result ).toHaveLength( 4 );
expect( result[ 0 ].key ).toBe( 'uncategorized_file' );
expect( result[ 0 ].label ).toBe(
'Prior undisputed transaction history'
);
expect( result ).toHaveLength( 6 ); // Default fields + 3 specific fields
expect( result[ 0 ].description ).toBe(
'Proof of past undisputed transactions from the same customer, with matching billing and device details'
);
expect( result[ 1 ].key ).toBe( 'receipt' );
expect( result[ 2 ].key ).toBe( 'customer_communication' );
expect( result[ 3 ].key ).toBe( 'refund_policy' );
} );

it( 'should return default fraudulent fields when feature flag is disabled', () => {
global.wcpaySettings.featureFlags.isDisputeAdditionalEvidenceTypesEnabled = false;

const result = getRecommendedDocumentFields(
'fraudulent',
undefined,
undefined,
'booking_reservation'
);

// Should return default fraudulent fields, not matrix fields
expect( result ).toHaveLength( 5 );
expect( result[ 0 ].key ).toBe( 'receipt' );
expect( result[ 1 ].key ).toBe( 'customer_communication' );
expect( result[ 2 ].key ).toBe( 'access_activity_log' );
expect( result[ 2 ].label ).toBe( 'Subscription logs' );
expect( result[ 2 ].description ).toBe(
'Order notes or the history of related orders. This should clearly show successful renewals before the dispute.'
);
expect( result[ 2 ].key ).toBe( 'customer_signature' );
expect( result[ 3 ].key ).toBe( 'refund_policy' );
expect( result[ 4 ].key ).toBe( 'cancellation_policy' );
expect( result[ 5 ].key ).toBe( 'uncategorized_file' );
expect( result[ 4 ].key ).toBe( 'uncategorized_file' );
} );

it( 'should return fields with subscription logs for subscription_canceled with digital product', () => {
it( 'should return default fields for fraudulent + physical_product even when feature flag is enabled', () => {
global.wcpaySettings.featureFlags.isDisputeAdditionalEvidenceTypesEnabled = true;

const result = getRecommendedDocumentFields(
'subscription_canceled',
'fraudulent',
undefined,
undefined,
'digital_product_or_service'
'physical_product'
);
expect( result ).toHaveLength( 6 );
expect( result[ 2 ].key ).toBe( 'access_activity_log' );
expect( result[ 2 ].label ).toBe( 'Subscription logs' );

// Should fall back to default fraudulent fields since no matrix entry exists
expect( result ).toHaveLength( 5 );
expect( result[ 0 ].key ).toBe( 'receipt' );
expect( result[ 2 ].key ).toBe( 'customer_signature' );
} );

it( 'should return fields without subscription logs for subscription_canceled with multiple product types', () => {
it( 'should return default fields for fraudulent when no product type is provided', () => {
global.wcpaySettings.featureFlags.isDisputeAdditionalEvidenceTypesEnabled = true;

const result = getRecommendedDocumentFields( 'fraudulent' );

// Should fall back to default fraudulent fields
expect( result ).toHaveLength( 5 );
expect( result[ 0 ].key ).toBe( 'receipt' );
} );

it( 'should return matrix fields for subscription_canceled + multiple when feature flag is enabled', () => {
global.wcpaySettings.featureFlags.isDisputeAdditionalEvidenceTypesEnabled = true;

const result = getRecommendedDocumentFields(
'subscription_canceled',
undefined,
undefined,
'multiple'
);
expect( result ).toHaveLength( 5 ); // Default fields + 2 specific fields (no subscription logs)

// Matrix entry for subscription_canceled + multiple (no subscription logs)
expect( result ).toHaveLength( 5 );
expect( result[ 0 ].key ).toBe( 'receipt' );
expect( result[ 1 ].key ).toBe( 'customer_communication' );
expect( result[ 2 ].key ).toBe( 'refund_policy' );
Expand All @@ -268,28 +348,80 @@ describe( 'Recommended Documents', () => {
expect( hasSubscriptionLogs ).toBe( false );
} );

it( 'should return fields with subscription logs for subscription_canceled with booking_reservation type', () => {
it( 'should return matrix fields for subscription_canceled + other when feature flag is enabled', () => {
global.wcpaySettings.featureFlags.isDisputeAdditionalEvidenceTypesEnabled = true;

const result = getRecommendedDocumentFields(
'subscription_canceled',
undefined,
undefined,
'other'
);

// Matrix entry for subscription_canceled + other (simplified fields)
expect( result ).toHaveLength( 2 );
expect( result[ 0 ].key ).toBe( 'receipt' );
expect( result[ 0 ].label ).toBe( 'Proof of Purchase' );
expect( result[ 1 ].key ).toBe( 'uncategorized_file' );
expect( result[ 1 ].label ).toBe( 'Order details' );
} );

it( 'should return matrix fields for duplicate + booking_reservation + is_duplicate when feature flag is enabled', () => {
global.wcpaySettings.featureFlags.isDisputeAdditionalEvidenceTypesEnabled = true;

const result = getRecommendedDocumentFields(
'duplicate',
undefined,
'is_duplicate',
'booking_reservation'
);
expect( result ).toHaveLength( 6 );
expect( result[ 2 ].key ).toBe( 'access_activity_log' );
expect( result[ 2 ].label ).toBe( 'Subscription logs' );

// Matrix entry for duplicate + booking_reservation + is_duplicate (Scenario A)
expect( result ).toHaveLength( 3 );
expect( result[ 0 ].key ).toBe( 'receipt' );
expect( result[ 0 ].label ).toBe( 'Order receipt' );
expect( result[ 1 ].key ).toBe( 'uncategorized_file' ); // Refund receipt
expect( result[ 1 ].label ).toBe( 'Refund receipt' );
expect( result[ 2 ].key ).toBe( 'refund_policy' );
} );

it( 'should return fields with subscription logs for subscription_canceled with offline_service type', () => {
it( 'should return matrix fields for duplicate + booking_reservation + is_not_duplicate when feature flag is enabled', () => {
global.wcpaySettings.featureFlags.isDisputeAdditionalEvidenceTypesEnabled = true;

const result = getRecommendedDocumentFields(
'subscription_canceled',
'duplicate',
undefined,
'is_not_duplicate',
'booking_reservation'
);

// Matrix entry for duplicate + booking_reservation + is_not_duplicate (Scenario B)
expect( result ).toHaveLength( 5 );
expect( result[ 0 ].key ).toBe( 'receipt' );
expect( result[ 1 ].key ).toBe(
'duplicate_charge_documentation'
);
expect( result[ 1 ].label ).toBe( 'Any additional receipts' );
expect( result[ 2 ].key ).toBe( 'customer_communication' );
expect( result[ 3 ].key ).toBe( 'refund_policy' );
expect( result[ 4 ].key ).toBe( 'uncategorized_file' );
} );

it( 'should fall back to default duplicate fields for physical_product when feature flag is enabled', () => {
global.wcpaySettings.featureFlags.isDisputeAdditionalEvidenceTypesEnabled = true;

const result = getRecommendedDocumentFields(
'duplicate',
undefined,
'offline_service'
'is_duplicate',
'physical_product'
);
expect( result ).toHaveLength( 6 );
expect( result[ 2 ].key ).toBe( 'access_activity_log' );
expect( result[ 2 ].label ).toBe( 'Subscription logs' );

// Should fall back to default duplicate fields since no matrix entry for physical_product
expect( result ).toHaveLength( 3 );
expect( result[ 0 ].key ).toBe( 'receipt' );
expect( result[ 1 ].key ).toBe( 'uncategorized_file' ); // Refund receipt
expect( result[ 2 ].key ).toBe( 'refund_policy' );
} );
} );
} );
Expand Down
18 changes: 18 additions & 0 deletions client/disputes/new-evidence/document-field-keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Document field keys used across different dispute types.
* These keys map to Stripe API evidence fields.
*/
// eslint-disable-next-line @typescript-eslint/naming-convention -- This is a constant object.
export const DOCUMENT_FIELD_KEYS = {
RECEIPT: 'receipt',
CUSTOMER_COMMUNICATION: 'customer_communication',
CUSTOMER_SIGNATURE: 'customer_signature',
UNCATEGORIZED_FILE: 'uncategorized_file',
REFUND_POLICY: 'refund_policy',
REFUND_RECEIPT_DOCUMENTATION: 'uncategorized_file',
DUPLICATE_CHARGE_DOCUMENTATION: 'duplicate_charge_documentation',
CANCELLATION_POLICY: 'cancellation_policy',
ACCESS_ACTIVITY_LOG: 'access_activity_log',
SERVICE_DOCUMENTATION: 'service_documentation',
SHIPPING_DOCUMENTATION: 'shipping_documentation',
} as const;
Loading
Loading