Initial commit
This commit is contained in:
14
apps/smoke-tests/.env.example
Normal file
14
apps/smoke-tests/.env.example
Normal file
@@ -0,0 +1,14 @@
|
||||
# Chain 138 Smoke Tests Configuration
|
||||
# Copy this file to .env and fill in your actual values
|
||||
|
||||
# Private key for test wallet (required for write operations)
|
||||
# IMPORTANT: Never commit .env file with real private keys!
|
||||
TEST_PRIVATE_KEY=your_private_key_here
|
||||
|
||||
# Optional: RPC endpoint override
|
||||
# Default: https://138.rpc.thirdweb.com
|
||||
TEST_RPC_URL=https://138.rpc.thirdweb.com
|
||||
|
||||
# Optional: Test recipient address for transfers
|
||||
# Default: 0x0000000000000000000000000000000000000001
|
||||
TEST_RECIPIENT=0x0000000000000000000000000000000000000001
|
||||
49
apps/smoke-tests/README.md
Normal file
49
apps/smoke-tests/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Smoke Tests
|
||||
|
||||
End-to-end smoke tests for all Chain 138 offerings.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Create `.env` file in this directory:
|
||||
```bash
|
||||
TEST_PRIVATE_KEY=your_private_key_here
|
||||
TEST_RPC_URL=https://138.rpc.thirdweb.com # Optional
|
||||
TEST_RECIPIENT=0x... # Optional, default test recipient
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
## Running Tests
|
||||
|
||||
Run all tests:
|
||||
```bash
|
||||
pnpm test
|
||||
```
|
||||
|
||||
Run specific test suite:
|
||||
```bash
|
||||
pnpm test:wallets
|
||||
pnpm test:x402
|
||||
pnpm test:bridge
|
||||
pnpm test:tokens
|
||||
pnpm test:ai
|
||||
pnpm test:http-api
|
||||
```
|
||||
|
||||
## Test Coverage
|
||||
|
||||
- **Wallets**: Connect, sign message, native transfer, chain switching
|
||||
- **x402**: Payment request creation, fulfillment, receipt verification, replay protection
|
||||
- **Bridge**: Route validation, quote generation, token lists
|
||||
- **Tokens**: ERC20 deploy, mint, transfer, balance queries
|
||||
- **AI**: Read actions (balance, block height), write actions (transfer), prompt validation
|
||||
- **HTTP API**: Client creation, configuration validation
|
||||
|
||||
## Notes
|
||||
|
||||
- Tests requiring write operations need `TEST_PRIVATE_KEY` set
|
||||
- Some tests may skip if private key is not provided
|
||||
- Tests use Chain 138 testnet/mainnet as configured
|
||||
41
apps/smoke-tests/package.json
Normal file
41
apps/smoke-tests/package.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "smoke-tests",
|
||||
"version": "0.1.0",
|
||||
"description": "Smoke tests for Chain 138 offerings",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"test:wallets": "vitest run src/wallets",
|
||||
"test:x402": "vitest run src/x402",
|
||||
"test:bridge": "vitest run src/bridge",
|
||||
"test:tokens": "vitest run src/tokens",
|
||||
"test:ai": "vitest run src/ai",
|
||||
"test:http-api": "vitest run src/http-api",
|
||||
"test:all": "vitest run"
|
||||
},
|
||||
"keywords": [
|
||||
"testing",
|
||||
"smoke-tests",
|
||||
"chain-138"
|
||||
],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dbis-thirdweb/chain": "workspace:*",
|
||||
"@dbis-thirdweb/wallets": "workspace:*",
|
||||
"@dbis-thirdweb/x402": "workspace:*",
|
||||
"@dbis-thirdweb/bridge": "workspace:*",
|
||||
"@dbis-thirdweb/tokens": "workspace:*",
|
||||
"@dbis-thirdweb/ai": "workspace:*",
|
||||
"@dbis-thirdweb/http-api": "workspace:*",
|
||||
"@thirdweb-dev/sdk": "^4.0.0",
|
||||
"ethers": "^5.7.0",
|
||||
"dotenv": "^16.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"vitest": "^1.0.0"
|
||||
}
|
||||
}
|
||||
90
apps/smoke-tests/src/ai/index.test.ts
Normal file
90
apps/smoke-tests/src/ai/index.test.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ThirdwebSDK } from '@thirdweb-dev/sdk';
|
||||
import { ethers } from 'ethers';
|
||||
import {
|
||||
createReadBalanceAction,
|
||||
createReadBlockHeightAction,
|
||||
createTransferAction,
|
||||
executeReadAction,
|
||||
createReadPrompt,
|
||||
validatePromptForChain138,
|
||||
validateChainId,
|
||||
} from '@dbis-thirdweb/ai';
|
||||
import { chain138 } from '@dbis-thirdweb/chain';
|
||||
import { testConfig } from '../config';
|
||||
|
||||
describe('AI Smoke Tests', () => {
|
||||
it('should create read balance action', () => {
|
||||
const action = createReadBalanceAction('0x1234567890123456789012345678901234567890');
|
||||
expect(action.type).toBe('read');
|
||||
expect(action.chainId).toBe(138);
|
||||
expect(action.operation).toBe('getBalance');
|
||||
});
|
||||
|
||||
it('should create read block height action', () => {
|
||||
const action = createReadBlockHeightAction();
|
||||
expect(action.type).toBe('read');
|
||||
expect(action.chainId).toBe(138);
|
||||
expect(action.operation).toBe('getBlockNumber');
|
||||
});
|
||||
|
||||
it('should create transfer action', () => {
|
||||
const action = createTransferAction(
|
||||
'0x1234567890123456789012345678901234567890',
|
||||
'1000000000000000000'
|
||||
);
|
||||
expect(action.type).toBe('write');
|
||||
expect(action.chainId).toBe(138);
|
||||
expect(action.operation).toBe('transferNative');
|
||||
});
|
||||
|
||||
it('should execute read balance action', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping read balance test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const provider = sdk.getProvider();
|
||||
const signer = await sdk.getSigner();
|
||||
const address = await signer.getAddress();
|
||||
|
||||
const action = createReadBalanceAction(address);
|
||||
const result = await executeReadAction(action, sdk, provider);
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
expect(typeof (result as { balance: string }).balance).toBe('string');
|
||||
});
|
||||
|
||||
it('should execute read block height action', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping block height test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const provider = sdk.getProvider();
|
||||
|
||||
const action = createReadBlockHeightAction();
|
||||
const result = await executeReadAction(action, sdk, provider);
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
expect((result as { blockNumber: number }).blockNumber).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should create chain-aware prompts', () => {
|
||||
const prompt = createReadPrompt('getBalance', { address: '0x...' });
|
||||
expect(prompt).toContain('Chain 138');
|
||||
expect(prompt).toContain('138');
|
||||
});
|
||||
|
||||
it('should validate prompts for Chain 138', () => {
|
||||
const validPrompt = 'Perform operation on Chain 138';
|
||||
expect(() => validatePromptForChain138(validPrompt)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should validate chain ID', () => {
|
||||
expect(() => validateChainId(138)).not.toThrow();
|
||||
expect(() => validateChainId(1)).toThrow();
|
||||
});
|
||||
});
|
||||
69
apps/smoke-tests/src/bridge/index.test.ts
Normal file
69
apps/smoke-tests/src/bridge/index.test.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ethers } from 'ethers';
|
||||
import {
|
||||
getSupportedRoutes,
|
||||
isRouteSupported,
|
||||
generateBridgeQuote,
|
||||
getAllBridgeableTokens,
|
||||
} from '@dbis-thirdweb/bridge';
|
||||
import { chain138 } from '@dbis-thirdweb/chain';
|
||||
|
||||
describe('Bridge Smoke Tests', () => {
|
||||
it('should get supported routes to Chain 138', () => {
|
||||
const routes = getSupportedRoutes();
|
||||
expect(routes.length).toBeGreaterThan(0);
|
||||
expect(routes.every((r) => r.toChainId === chain138.chainId)).toBe(true);
|
||||
});
|
||||
|
||||
it('should check if route is supported', () => {
|
||||
expect(isRouteSupported(1, 138)).toBe(true); // Ethereum to Chain 138
|
||||
expect(isRouteSupported(138, 1)).toBe(false); // Chain 138 to Ethereum (not supported)
|
||||
});
|
||||
|
||||
it('should get bridgeable tokens', () => {
|
||||
const tokens = getAllBridgeableTokens();
|
||||
expect(tokens.length).toBeGreaterThan(0);
|
||||
const nativeToken = tokens.find((t) => t.isNative);
|
||||
expect(nativeToken).toBeTruthy();
|
||||
expect(nativeToken?.symbol).toBe('ETH');
|
||||
});
|
||||
|
||||
it('should generate bridge quote', async () => {
|
||||
const tokens = getAllBridgeableTokens();
|
||||
const nativeToken = tokens.find((t) => t.isNative);
|
||||
expect(nativeToken).toBeTruthy();
|
||||
|
||||
const quote = await generateBridgeQuote({
|
||||
fromChainId: 1,
|
||||
toChainId: 138,
|
||||
token: nativeToken!,
|
||||
amount: ethers.utils.parseEther('0.1'),
|
||||
slippageBps: 50,
|
||||
});
|
||||
|
||||
expect(quote.fromChainId).toBe(1);
|
||||
expect(quote.toChainId).toBe(138);
|
||||
expect(quote.token).toBe(nativeToken);
|
||||
expect(quote.amount).toBe(ethers.utils.parseEther('0.1'));
|
||||
expect(quote.estimatedOutput).toBeGreaterThan(0n);
|
||||
expect(quote.fee).toBeGreaterThanOrEqual(0n);
|
||||
expect(quote.minimumOutput).toBeLessThanOrEqual(quote.estimatedOutput);
|
||||
});
|
||||
|
||||
it('should validate quote', async () => {
|
||||
const tokens = getAllBridgeableTokens();
|
||||
const nativeToken = tokens.find((t) => t.isNative);
|
||||
expect(nativeToken).toBeTruthy();
|
||||
|
||||
const quote = await generateBridgeQuote({
|
||||
fromChainId: 1,
|
||||
toChainId: 138,
|
||||
token: nativeToken!,
|
||||
amount: ethers.utils.parseEther('0.1'),
|
||||
});
|
||||
|
||||
// Quote should be valid
|
||||
expect(quote.amount).toBeGreaterThan(0n);
|
||||
expect(quote.estimatedOutput).toBeGreaterThan(0n);
|
||||
});
|
||||
});
|
||||
26
apps/smoke-tests/src/config.ts
Normal file
26
apps/smoke-tests/src/config.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'dotenv/config';
|
||||
|
||||
/**
|
||||
* Test configuration
|
||||
*/
|
||||
export const testConfig = {
|
||||
/**
|
||||
* Private key for test wallet (required for write operations)
|
||||
* Set via TEST_PRIVATE_KEY environment variable
|
||||
*/
|
||||
privateKey: process.env.TEST_PRIVATE_KEY || '',
|
||||
|
||||
/**
|
||||
* RPC endpoint override (optional)
|
||||
*/
|
||||
rpcUrl: process.env.TEST_RPC_URL,
|
||||
|
||||
/**
|
||||
* Test recipient address (optional)
|
||||
*/
|
||||
testRecipient: process.env.TEST_RECIPIENT || '0x0000000000000000000000000000000000000001',
|
||||
};
|
||||
|
||||
if (!testConfig.privateKey) {
|
||||
console.warn('WARNING: TEST_PRIVATE_KEY not set. Write operations will fail.');
|
||||
}
|
||||
48
apps/smoke-tests/src/http-api/index.test.ts
Normal file
48
apps/smoke-tests/src/http-api/index.test.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { createAPIClient, createChain138API } from '@dbis-thirdweb/http-api';
|
||||
|
||||
describe('HTTP API Smoke Tests', () => {
|
||||
it('should create API client', () => {
|
||||
const client = createAPIClient({
|
||||
timeout: 30000,
|
||||
retries: 3,
|
||||
});
|
||||
|
||||
expect(client).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should create Chain 138 API client', () => {
|
||||
const api = createChain138API({
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
expect(api).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should have chain 138 configuration', () => {
|
||||
const api = createChain138API();
|
||||
// API client should be configured for Chain 138
|
||||
expect(api).toBeTruthy();
|
||||
});
|
||||
|
||||
// Note: Actual API endpoint tests would require:
|
||||
// 1. Valid API key
|
||||
// 2. Actual thirdweb API endpoints for Chain 138
|
||||
// 3. Network access
|
||||
// These are placeholders for when API is fully configured
|
||||
|
||||
it('should handle timeout configuration', () => {
|
||||
const client = createAPIClient({
|
||||
timeout: 5000,
|
||||
});
|
||||
expect(client).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should handle retry configuration', () => {
|
||||
const client = createAPIClient({
|
||||
retries: 5,
|
||||
retryDelay: 2000,
|
||||
});
|
||||
expect(client).toBeTruthy();
|
||||
});
|
||||
});
|
||||
11
apps/smoke-tests/src/index.ts
Normal file
11
apps/smoke-tests/src/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Unified smoke test runner for all Chain 138 offerings
|
||||
* Run with: pnpm test
|
||||
*/
|
||||
|
||||
export * from './wallets/index.test';
|
||||
export * from './x402/index.test';
|
||||
export * from './bridge/index.test';
|
||||
export * from './tokens/index.test';
|
||||
export * from './ai/index.test';
|
||||
export * from './http-api/index.test';
|
||||
106
apps/smoke-tests/src/tokens/index.test.ts
Normal file
106
apps/smoke-tests/src/tokens/index.test.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ThirdwebSDK } from '@thirdweb-dev/sdk';
|
||||
import { ethers } from 'ethers';
|
||||
import {
|
||||
createTokenFactory,
|
||||
deployERC20,
|
||||
mintERC20,
|
||||
transferERC20,
|
||||
getERC20Balance,
|
||||
} from '@dbis-thirdweb/tokens';
|
||||
import { chain138 } from '@dbis-thirdweb/chain';
|
||||
import { testConfig } from '../config';
|
||||
|
||||
describe('Tokens Smoke Tests', () => {
|
||||
it('should create token factory', () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping factory test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const factory = createTokenFactory(sdk);
|
||||
expect(factory).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should deploy ERC20 token', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping ERC20 deploy test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const contractAddress = await deployERC20(sdk, {
|
||||
name: 'Test Token',
|
||||
symbol: 'TEST',
|
||||
description: 'Test token for smoke tests',
|
||||
initialSupply: ethers.utils.parseEther('1000000'),
|
||||
});
|
||||
|
||||
expect(contractAddress).toBeTruthy();
|
||||
expect(ethers.isAddress(contractAddress)).toBe(true);
|
||||
|
||||
// Verify contract exists
|
||||
const contract = await sdk.getContract(contractAddress, 'token');
|
||||
const name = await contract.call('name');
|
||||
expect(name).toBe('Test Token');
|
||||
});
|
||||
|
||||
it('should mint ERC20 tokens', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping mint test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const signer = await sdk.getSigner();
|
||||
const recipient = await signer.getAddress();
|
||||
|
||||
// Deploy token first
|
||||
const contractAddress = await deployERC20(sdk, {
|
||||
name: 'Mint Test Token',
|
||||
symbol: 'MTT',
|
||||
});
|
||||
|
||||
// Mint tokens
|
||||
const amount = ethers.utils.parseEther('1000');
|
||||
await mintERC20(sdk, contractAddress, amount, recipient);
|
||||
|
||||
// Check balance
|
||||
const balance = await getERC20Balance(sdk, contractAddress, recipient);
|
||||
expect(balance).toBeGreaterThanOrEqual(amount);
|
||||
});
|
||||
|
||||
it('should transfer ERC20 tokens', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping transfer test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const signer = await sdk.getSigner();
|
||||
const fromAddress = await signer.getAddress();
|
||||
|
||||
// Deploy and mint tokens
|
||||
const contractAddress = await deployERC20(sdk, {
|
||||
name: 'Transfer Test Token',
|
||||
symbol: 'TTT',
|
||||
initialSupply: ethers.utils.parseEther('10000'),
|
||||
});
|
||||
|
||||
// Transfer tokens
|
||||
const transferAmount = ethers.utils.parseEther('100');
|
||||
await transferERC20(sdk, contractAddress, testConfig.testRecipient, transferAmount);
|
||||
|
||||
// Check recipient balance
|
||||
const recipientBalance = await getERC20Balance(sdk, contractAddress, testConfig.testRecipient);
|
||||
expect(recipientBalance).toBeGreaterThanOrEqual(transferAmount);
|
||||
});
|
||||
|
||||
it('should handle token metadata', () => {
|
||||
// Test metadata utilities exist
|
||||
const { defaultMetadataConfig } = require('@dbis-thirdweb/tokens');
|
||||
expect(defaultMetadataConfig).toBeTruthy();
|
||||
expect(defaultMetadataConfig.ipfsGateway).toBeTruthy();
|
||||
});
|
||||
});
|
||||
86
apps/smoke-tests/src/wallets/index.test.ts
Normal file
86
apps/smoke-tests/src/wallets/index.test.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ThirdwebSDK } from '@thirdweb-dev/sdk';
|
||||
import { chain138, getWalletConfig } from '@dbis-thirdweb/wallets';
|
||||
import { testConfig } from '../config';
|
||||
|
||||
describe('Wallets Smoke Tests', () => {
|
||||
it('should get wallet config for Chain 138', () => {
|
||||
const config = getWalletConfig();
|
||||
expect(config.confirmationBlocks).toBeGreaterThan(0);
|
||||
expect(config.rpcFailover.primary).toContain('138');
|
||||
});
|
||||
|
||||
it('should create SDK instance with Chain 138', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping SDK test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const chainId = await sdk.getChainId();
|
||||
expect(chainId).toBe(138);
|
||||
});
|
||||
|
||||
it('should connect and get chain ID', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping connection test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const address = await sdk.wallet.getAddress();
|
||||
expect(address).toBeTruthy();
|
||||
|
||||
const chainId = await sdk.getChainId();
|
||||
expect(chainId).toBe(138);
|
||||
});
|
||||
|
||||
it('should sign a message', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping sign message test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const message = 'Test message for Chain 138';
|
||||
const signature = await sdk.wallet.sign(message);
|
||||
expect(signature).toBeTruthy();
|
||||
expect(signature.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should send native token transfer', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping native transfer test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const provider = sdk.getProvider();
|
||||
const signer = await sdk.getSigner();
|
||||
|
||||
// Get initial balance
|
||||
const fromAddress = await signer.getAddress();
|
||||
const initialBalance = await provider.getBalance(fromAddress);
|
||||
|
||||
// Send small amount (0.001 ETH)
|
||||
const amount = BigInt('1000000000000000'); // 0.001 ETH
|
||||
const tx = await signer.sendTransaction({
|
||||
to: testConfig.testRecipient,
|
||||
value: amount,
|
||||
});
|
||||
|
||||
expect(tx.hash).toBeTruthy();
|
||||
|
||||
// Wait for confirmation
|
||||
const receipt = await provider.waitForTransaction(tx.hash, 1);
|
||||
expect(receipt).toBeTruthy();
|
||||
expect(receipt.status).toBe(1);
|
||||
});
|
||||
|
||||
it('should verify chain switching utilities', () => {
|
||||
// Verify chain138 export
|
||||
expect(chain138).toBeTruthy();
|
||||
expect(chain138.chainId).toBe(138);
|
||||
expect(chain138.rpc.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
116
apps/smoke-tests/src/x402/index.test.ts
Normal file
116
apps/smoke-tests/src/x402/index.test.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ThirdwebSDK } from '@thirdweb-dev/sdk';
|
||||
import { ethers } from 'ethers';
|
||||
import {
|
||||
PayToAccessFlow,
|
||||
InMemoryReplayProtectionStore,
|
||||
type PaymentRequest,
|
||||
} from '@dbis-thirdweb/x402';
|
||||
import { chain138 } from '@dbis-thirdweb/chain';
|
||||
import { testConfig } from '../config';
|
||||
|
||||
describe('x402 Smoke Tests', () => {
|
||||
it('should create payment request', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping x402 test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const provider = sdk.getProvider();
|
||||
const replayStore = new InMemoryReplayProtectionStore();
|
||||
const flow = new PayToAccessFlow(provider, replayStore);
|
||||
|
||||
const request = await flow.createRequest({
|
||||
amount: ethers.utils.parseEther('0.001'),
|
||||
recipient: testConfig.testRecipient,
|
||||
expiresInSeconds: 3600,
|
||||
});
|
||||
|
||||
expect(request.requestId).toBeTruthy();
|
||||
expect(request.amount).toBe(ethers.utils.parseEther('0.001'));
|
||||
expect(request.recipient).toBe(testConfig.testRecipient);
|
||||
});
|
||||
|
||||
it('should generate challenge from request', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping challenge test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const provider = sdk.getProvider();
|
||||
const replayStore = new InMemoryReplayProtectionStore();
|
||||
const flow = new PayToAccessFlow(provider, replayStore);
|
||||
|
||||
const request = await flow.createRequest({
|
||||
amount: ethers.utils.parseEther('0.001'),
|
||||
recipient: testConfig.testRecipient,
|
||||
expiresInSeconds: 3600,
|
||||
});
|
||||
|
||||
const challenge = flow.generateChallenge(request);
|
||||
expect(challenge.request.requestId).toBe(request.requestId);
|
||||
expect(challenge.nonce).toBeTruthy();
|
||||
expect(challenge.message).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should fulfill payment and verify receipt', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping fulfillment test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const provider = sdk.getProvider();
|
||||
const signer = await sdk.getSigner();
|
||||
const replayStore = new InMemoryReplayProtectionStore();
|
||||
const flow = new PayToAccessFlow(provider, replayStore);
|
||||
|
||||
// Create request
|
||||
const request = await flow.createRequest({
|
||||
amount: ethers.utils.parseEther('0.001'),
|
||||
recipient: testConfig.testRecipient,
|
||||
expiresInSeconds: 3600,
|
||||
});
|
||||
|
||||
// Generate challenge
|
||||
const challenge = flow.generateChallenge(request);
|
||||
|
||||
// Fulfill payment
|
||||
const receipt = await flow.fulfillPayment(challenge, signer);
|
||||
expect(receipt.txHash).toBeTruthy();
|
||||
expect(receipt.requestId).toBe(request.requestId);
|
||||
expect(receipt.blockNumber).toBeGreaterThan(0);
|
||||
|
||||
// Verify payment
|
||||
const isValid = await flow.verifyPayment(receipt, request);
|
||||
expect(isValid).toBe(true);
|
||||
});
|
||||
|
||||
it('should prevent replay attacks', async () => {
|
||||
if (!testConfig.privateKey) {
|
||||
console.log('Skipping replay protection test - no private key');
|
||||
return;
|
||||
}
|
||||
|
||||
const sdk = new ThirdwebSDK(chain138, testConfig.privateKey);
|
||||
const provider = sdk.getProvider();
|
||||
const replayStore = new InMemoryReplayProtectionStore();
|
||||
const flow = new PayToAccessFlow(provider, replayStore);
|
||||
|
||||
const request = await flow.createRequest({
|
||||
amount: ethers.utils.parseEther('0.001'),
|
||||
recipient: testConfig.testRecipient,
|
||||
expiresInSeconds: 3600,
|
||||
});
|
||||
|
||||
// First request should succeed
|
||||
await expect(flow.createRequest({
|
||||
amount: ethers.utils.parseEther('0.001'),
|
||||
recipient: testConfig.testRecipient,
|
||||
expiresInSeconds: 3600,
|
||||
metadata: request.requestId, // Use same request ID to test replay protection
|
||||
})).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
18
apps/smoke-tests/tsconfig.json
Normal file
18
apps/smoke-tests/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"composite": false
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"references": [
|
||||
{ "path": "../../packages/chain" },
|
||||
{ "path": "../../packages/wallets" },
|
||||
{ "path": "../../packages/x402" },
|
||||
{ "path": "../../packages/bridge" },
|
||||
{ "path": "../../packages/tokens" },
|
||||
{ "path": "../../packages/ai" },
|
||||
{ "path": "../../packages/http-api" }
|
||||
]
|
||||
}
|
||||
10
apps/smoke-tests/vitest.config.ts
Normal file
10
apps/smoke-tests/vitest.config.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'node',
|
||||
testTimeout: 60000,
|
||||
hookTimeout: 60000,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user