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
1,810 changes: 577 additions & 1,233 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
"name": "design-patterns-monorepo",
"private": true,
"devDependencies": {
"@types/jest": "^29.5.14",
"turbo": "^1.10.0"
},
"scripts": {
"test": "turbo run test"
},
"workspaces": ["packages/*"]
"workspaces": [
"packages/*"
]
}
9 changes: 8 additions & 1 deletion packages/adapter/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
/** @type {import('ts-jest').JestConfigWithTsJest} **/
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
testMatch: ["**/__tests__/**/*.test.ts", "**/?(*.)+(spec|test).ts"],
transform: {
"^.+\.tsx?$": ["ts-jest",{}],
"^.+\.tsx?$": ["ts-jest", {
tsconfig: "tsconfig.json"
}],
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
}
};
1 change: 0 additions & 1 deletion packages/adapter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"test": "jest"
},
"devDependencies": {
"@types/jest": "^29.5.14",
"jest": "^29.7.0",
"ts-jest": "^29.1.0",
"typescript": "^5.3.0"
Expand Down
23 changes: 23 additions & 0 deletions packages/adapter/src/adapters/PayPalAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { IPaymentProcessor } from '../interfaces/IPaymentProcessor';
import { PayPal } from '../payment/PayPal';

// The PayPalAdapter class implements the IPaymentProcessor interface and adapts the PayPal payment processing system to fit the interface.


export class PayPalAdapter implements IPaymentProcessor {
private paypal: PayPal;

constructor(paypal: PayPal) {
this.paypal = paypal;
}
processPayment(amount: number): void {
const transactionId = this.paypal.makePayment(amount, 'USD');
console.log(`Payment processed with PayPal. Transaction ID: ${transactionId}`);
}

verifytransaction(transactionId: string): boolean {
const result = this.paypal.checkPayment(transactionId);
return result.status === 'Completed';
}
}

21 changes: 21 additions & 0 deletions packages/adapter/src/adapters/StripeAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { IPaymentProcessor } from "../interfaces/IPaymentProcessor";
import { Stripe } from "../payment/Stripe"; // Adjust the path as needed

export class StripeAdapter implements IPaymentProcessor{
private stripe: Stripe;

constructor(stripe: Stripe){
this.stripe= new Stripe();
}

processPayment(amont: number): void {
const amountInCents = amont * 100; // Convert to cents
const charge= this.stripe.charge(amountInCents, 'adapte payment');
console.log(`Payment processed with charge Transaction ID: ${charge.id}`);
}

verifytransaction(transactionId: string): boolean {
const charge = this.stripe.retrieveCharge(transactionId);
return charge.paid;
}
}
52 changes: 31 additions & 21 deletions packages/adapter/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
class SubsystemA {
operationA(): string {
return 'SubsystemA: Ready!';
}
import { IPaymentProcessor } from "./interfaces/IPaymentProcessor";
import { PayPalAdapter } from "./adapters/PayPalAdapter";
import { StripeAdapter } from "./adapters/StripeAdapter";
import { PayPal } from "@/payment/PayPal";
import { Stripe } from "./payment/Stripe";

export class PaymentService {
constructor(private paymentProcessor: IPaymentProcessor) { }

executePayment(amount: number): void {
this.paymentProcessor.processPayment(amount);
}

class SubsystemB {
operationB(): string {
return 'SubsystemB: Working!';
}

verifyPayment(transactionId: string): void {
const isValid = this.paymentProcessor.verifytransaction(transactionId);
console.log(`Transaction ${transactionId} is ${isValid ? 'valid' : 'invalid'}`);
}

export class Adapter {
private subsystemA = new SubsystemA();
private subsystemB = new SubsystemB();

public operation(): string {
const resultA = this.subsystemA.operationA();
const resultB = this.subsystemB.operationB();
return `${resultA} ${resultB}`;
}
}

}

// Uso con PayPal
console.log('=== Using PayPal via Adapter ===');
const paypal = new PayPal();
const paypalAdapter = new PayPalAdapter(paypal);
const paypalService = new PaymentService(paypalAdapter);
paypalService.executePayment(100);
paypalService.verifyPayment('paypal-trans-abc123');

console.log('\n=== Using Stripe via Adapter ===');
const stripe = new Stripe();
const stripeAdapter = new StripeAdapter(stripe);
const stripeService = new PaymentService(stripeAdapter);
stripeService.executePayment(100);
stripeService.verifyPayment('stripe-charge-xyz789');
4 changes: 4 additions & 0 deletions packages/adapter/src/interfaces/IPaymentProcessor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface IPaymentProcessor {
processPayment(amont: number): void;
verifytransaction(transactionId: string): boolean;
}
11 changes: 11 additions & 0 deletions packages/adapter/src/payment/PayPal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export class PayPal {
makePayment(amount: number, currency: string): string {
// Implementation here
return 'transaction-id';
}

checkPayment(transactionId: string): { status: string; amount: number } {
// Implementation here
return { status: 'completed', amount: 100 };
}
}
11 changes: 11 additions & 0 deletions packages/adapter/src/payment/Stripe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export class Stripe{
charge(amounInCents: number, description: string):{id: string}{
console.log(`Stripe charge ${amounInCents} cents for ${description}`);
return {id: `stripe-transaction-${Math.random().toString(36).substring(2,10)}`} ;
}

retrieveCharge(chargeId: string):{paid:boolean; amount: number }{
console.log(`retrieving Stripe charge ${chargeId}`);
return {paid: true, amount: 100} ;
}
}
70 changes: 70 additions & 0 deletions packages/adapter/test/PayPalAdapter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { PayPalAdapter } from '../src/adapters/PayPalAdapter';
import { PayPal } from '@/payment/PayPal';

jest.mock('@/payment/PayPal');

describe('PayPalAdapter', () => {
let paypalAdapter: PayPalAdapter;
let mockPayPal: jest.Mocked<PayPal>;

beforeEach(() => {
mockPayPal = new PayPal() as jest.Mocked<PayPal>;
(PayPal as jest.Mock).mockImplementation(() => mockPayPal);
paypalAdapter = new PayPalAdapter(mockPayPal);
});

afterEach(() => {
jest.clearAllMocks();
});

describe('processPayment', () => {
it('should call PayPal makePayment with correct amount', () => {
const amount = 100;
const mockTransactionId = 'paypal-trans-123';
mockPayPal.makePayment.mockReturnValue(mockTransactionId);

paypalAdapter.processPayment(amount);

expect(mockPayPal.makePayment).toHaveBeenCalledWith(amount, 'USD');
});

it('should return void and log transaction ID', () => {
const consoleSpy = jest.spyOn(console, 'log');
const mockTransactionId = 'paypal-trans-123';
mockPayPal.makePayment.mockReturnValue(mockTransactionId);

paypalAdapter.processPayment(100);

expect(consoleSpy).toHaveBeenCalledWith(
expect.stringContaining(mockTransactionId)
);
});
});

describe('verifyTransaction', () => {
it('should return true when PayPal checkPayment returns Completed status', () => {
const transactionId = 'paypal-trans-123';
mockPayPal.checkPayment.mockReturnValue({
status: 'Completed',
amount: 100,
});

const result = paypalAdapter.verifytransaction(transactionId);

expect(mockPayPal.checkPayment).toHaveBeenCalledWith(transactionId);
expect(result).toBe(true);
});

it('should return false when PayPal checkPayment returns non-Completed status', () => {
const transactionId = 'paypal-trans-123';
mockPayPal.checkPayment.mockReturnValue({
status: 'Failed',
amount: 100,
});

const result = paypalAdapter.verifytransaction(transactionId);

expect(result).toBe(false);
});
});
});
73 changes: 73 additions & 0 deletions packages/adapter/test/StripeAdapter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { StripeAdapter } from '../src/adapters/StripeAdapter';
import { Stripe } from '../src/payment/Stripe';

jest.mock('../src/payment/Stripe');

describe('StripeAdapter', () => {
let stripeAdapter: StripeAdapter;
let mockStripe: jest.Mocked<Stripe>;

beforeEach(() => {
mockStripe = new Stripe() as jest.Mocked<Stripe>;
(Stripe as jest.Mock).mockImplementation(() => mockStripe);
stripeAdapter = new StripeAdapter(mockStripe);
});

afterEach(() => {
jest.clearAllMocks();
});

describe('processPayment', () => {
it('should call Stripe charge with amount in cents', () => {
const amount = 100;
const mockChargeId = 'stripe-charge-123';
mockStripe.charge.mockReturnValue({ id: mockChargeId });

stripeAdapter.processPayment(amount);

expect(mockStripe.charge).toHaveBeenCalledWith(
10000,
'adapte payment'
);
});

it('should return void and log charge ID', () => {
const consoleSpy = jest.spyOn(console, 'log');
const mockChargeId = 'stripe-charge-123';
mockStripe.charge.mockReturnValue({ id: mockChargeId });

stripeAdapter.processPayment(100);

expect(consoleSpy).toHaveBeenCalledWith(
expect.stringContaining(mockChargeId)
);
});
});

describe('verifyTransaction', () => {
it('should return true when Stripe retrieveCharge returns paid true', () => {
const chargeId = 'stripe-charge-123';
mockStripe.retrieveCharge.mockReturnValue({
paid: true,
amount: 10000,
});

const result = stripeAdapter.verifytransaction(chargeId);

expect(mockStripe.retrieveCharge).toHaveBeenCalledWith(chargeId);
expect(result).toBe(true);
});

it('should return false when Stripe retrieveCharge returns paid false', () => {
const chargeId = 'stripe-charge-123';
mockStripe.retrieveCharge.mockReturnValue({
paid: false,
amount: 10000,
});

const result = stripeAdapter.verifytransaction(chargeId);

expect(result).toBe(false);
});
});
});
51 changes: 51 additions & 0 deletions packages/adapter/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { PaymentService } from '../src/index';
import { IPaymentProcessor } from '../src/interfaces/IPaymentProcessor';

describe('PaymentService', () => {
let mockPaymentProcessor: jest.Mocked<IPaymentProcessor>;
let paymentService: PaymentService;

beforeEach(() => {
mockPaymentProcessor = {
processPayment: jest.fn(),
verifytransaction: jest.fn().mockReturnValue(true),
};
paymentService = new PaymentService(mockPaymentProcessor);
});

afterEach(() => {
jest.clearAllMocks();
});

describe('executePayment', () => {
it('should call processPayment on the payment processor', () => {
const amount = 100;
paymentService.executePayment(amount);

expect(mockPaymentProcessor.processPayment).toHaveBeenCalledWith(amount);
});
});

describe('verifyPayment', () => {
it('should call verifyTransaction on the payment processor', () => {
const transactionId = 'test-transaction-123';
paymentService.verifyPayment(transactionId);

expect(mockPaymentProcessor.verifytransaction).toHaveBeenCalledWith(
transactionId
);
});

it('should log the verification result', () => {
const consoleSpy = jest.spyOn(console, 'log');
const transactionId = 'test-transaction-123';
mockPaymentProcessor.verifytransaction.mockReturnValue(true);

paymentService.verifyPayment(transactionId);

expect(consoleSpy).toHaveBeenCalledWith(
`Transaction ${transactionId} is valid`
);
});
});
});
9 changes: 0 additions & 9 deletions packages/adapter/tests/index.test.ts

This file was deleted.

Loading