fill stake e2e
This commit is contained in:
parent
30ed4aa072
commit
aa1ddfcecd
6 changed files with 610 additions and 12 deletions
25
scripts/quick-screenshot.mjs
Normal file
25
scripts/quick-screenshot.mjs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env node
|
||||
import { chromium } from '@playwright/test';
|
||||
|
||||
const ACCOUNT_ADDRESS = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266';
|
||||
const WEBAPP_URL = 'http://localhost:8081';
|
||||
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const context = await browser.newContext();
|
||||
|
||||
// Set auth
|
||||
await context.addInitScript(() => {
|
||||
window.localStorage.setItem('authentificated', 'true');
|
||||
});
|
||||
|
||||
const page = await context.newPage();
|
||||
|
||||
console.log('Loading stake page...');
|
||||
await page.goto(`${WEBAPP_URL}/app/#/stake`, { waitUntil: 'networkidle' });
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
console.log('Taking screenshot...');
|
||||
await page.screenshot({ path: 'stake-page-final.png', fullPage: true });
|
||||
console.log('Screenshot saved to stake-page-final.png');
|
||||
|
||||
await browser.close();
|
||||
171
scripts/screenshot-stake-page.mjs
Normal file
171
scripts/screenshot-stake-page.mjs
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
#!/usr/bin/env node
|
||||
import { chromium } from '@playwright/test';
|
||||
import { Wallet } from 'ethers';
|
||||
|
||||
const ACCOUNT_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
|
||||
const ACCOUNT_ADDRESS = new Wallet(ACCOUNT_PRIVATE_KEY).address.toLowerCase();
|
||||
const STACK_RPC_URL = 'http://127.0.0.1:8545';
|
||||
const STACK_WEBAPP_URL = 'http://localhost:8081';
|
||||
|
||||
const chainId = 31337;
|
||||
const chainIdHex = `0x${chainId.toString(16)}`;
|
||||
|
||||
async function takeScreenshot() {
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
|
||||
const context = await browser.newContext();
|
||||
|
||||
// Set auth flag
|
||||
await context.addInitScript(() => {
|
||||
window.localStorage.setItem('authentificated', 'true');
|
||||
});
|
||||
|
||||
// Inject wallet provider
|
||||
await context.addInitScript(
|
||||
({ account, chainIdHex: cidHex, chainId: cid, rpcEndpoint }) => {
|
||||
const listeners = new Map();
|
||||
let rpcRequestId = 0;
|
||||
let connected = false;
|
||||
|
||||
const emit = (event, payload) => {
|
||||
const handlers = listeners.get(event);
|
||||
if (!handlers) return;
|
||||
for (const handler of Array.from(handlers)) {
|
||||
try {
|
||||
handler(payload);
|
||||
} catch (error) {
|
||||
console.error(`[wallet-provider] listener for ${event} failed`, error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const sendRpc = async (method, params) => {
|
||||
rpcRequestId += 1;
|
||||
const response = await fetch(rpcEndpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({ jsonrpc: '2.0', id: rpcRequestId, method, params }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`RPC call to ${method} failed with status ${response.status}`);
|
||||
}
|
||||
|
||||
const payload = await response.json();
|
||||
if (payload?.error) {
|
||||
throw new Error(payload.error?.message ?? 'RPC error');
|
||||
}
|
||||
return payload.result;
|
||||
};
|
||||
|
||||
const provider = {
|
||||
isMetaMask: true,
|
||||
isPlaywrightWallet: true,
|
||||
isConnected: () => connected,
|
||||
selectedAddress: account,
|
||||
chainId: cidHex,
|
||||
networkVersion: String(cid),
|
||||
request: async ({ method, params = [] }) => {
|
||||
const args = Array.isArray(params) ? params.slice() : [];
|
||||
|
||||
switch (method) {
|
||||
case 'eth_requestAccounts':
|
||||
connected = true;
|
||||
provider.selectedAddress = account;
|
||||
provider.chainId = cidHex;
|
||||
provider.networkVersion = String(cid);
|
||||
emit('connect', { chainId: cidHex });
|
||||
emit('chainChanged', cidHex);
|
||||
emit('accountsChanged', [account]);
|
||||
return [account];
|
||||
case 'eth_accounts':
|
||||
return [account];
|
||||
case 'eth_chainId':
|
||||
return cidHex;
|
||||
case 'net_version':
|
||||
return String(cid);
|
||||
case 'wallet_switchEthereumChain':
|
||||
return null;
|
||||
case 'wallet_addEthereumChain':
|
||||
return null;
|
||||
case 'eth_sendTransaction': {
|
||||
const [tx = {}] = args;
|
||||
const enrichedTx = { ...tx, from: account };
|
||||
return sendRpc(method, [enrichedTx]);
|
||||
}
|
||||
default:
|
||||
return sendRpc(method, args);
|
||||
}
|
||||
},
|
||||
on: (event, listener) => {
|
||||
const handlers = listeners.get(event) ?? new Set();
|
||||
handlers.add(listener);
|
||||
listeners.set(event, handlers);
|
||||
if (event === 'connect' && connected) {
|
||||
listener({ chainId: cidHex });
|
||||
}
|
||||
return provider;
|
||||
},
|
||||
removeListener: (event, listener) => {
|
||||
const handlers = listeners.get(event);
|
||||
if (handlers) {
|
||||
handlers.delete(listener);
|
||||
}
|
||||
return provider;
|
||||
},
|
||||
enable: () => provider.request({ method: 'eth_requestAccounts' }),
|
||||
};
|
||||
|
||||
Object.defineProperty(window, 'ethereum', {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
value: provider,
|
||||
writable: false,
|
||||
});
|
||||
|
||||
provider.providers = [provider];
|
||||
window.dispatchEvent(new Event('ethereum#initialized'));
|
||||
},
|
||||
{
|
||||
account: ACCOUNT_ADDRESS,
|
||||
chainIdHex,
|
||||
chainId,
|
||||
rpcEndpoint: STACK_RPC_URL,
|
||||
}
|
||||
);
|
||||
|
||||
const page = await context.newPage();
|
||||
|
||||
console.log('Navigating to app...');
|
||||
await page.goto(`${STACK_WEBAPP_URL}/app/`, { waitUntil: 'domcontentloaded' });
|
||||
|
||||
// Wait for wallet to initialize
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// Check if wallet is visible (connected)
|
||||
try {
|
||||
const walletDisplay = page.getByText(/0xf39F/i).first();
|
||||
await walletDisplay.waitFor({ timeout: 10000 });
|
||||
console.log('Wallet connected!');
|
||||
} catch (e) {
|
||||
console.log('Wallet connection not detected, continuing anyway...');
|
||||
}
|
||||
|
||||
console.log('Navigating to stake page...');
|
||||
await page.goto(`${STACK_WEBAPP_URL}/app/#/stake`, { waitUntil: 'networkidle' });
|
||||
|
||||
// Wait for positions to load
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
console.log('Taking screenshot...');
|
||||
await page.screenshot({
|
||||
path: 'test-results/stake-page-after-test.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
console.log('Screenshot saved to test-results/stake-page-after-test.png');
|
||||
|
||||
await browser.close();
|
||||
}
|
||||
|
||||
takeScreenshot().catch(console.error);
|
||||
257
tests/e2e/02-max-stake-all-tax-rates.spec.ts
Normal file
257
tests/e2e/02-max-stake-all-tax-rates.spec.ts
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
import { expect, test, type APIRequestContext } from '@playwright/test';
|
||||
import { Wallet } from 'ethers';
|
||||
import { createWalletContext } from '../setup/wallet-provider';
|
||||
import { getStackConfig, validateStackHealthy } from '../setup/stack';
|
||||
import { TAX_RATE_OPTIONS } from '../../kraiken-lib/src/taxRates';
|
||||
|
||||
const ACCOUNT_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
|
||||
const ACCOUNT_ADDRESS = new Wallet(ACCOUNT_PRIVATE_KEY).address.toLowerCase();
|
||||
|
||||
// Get stack configuration from environment (or defaults)
|
||||
const STACK_CONFIG = getStackConfig();
|
||||
const STACK_RPC_URL = STACK_CONFIG.rpcUrl;
|
||||
const STACK_WEBAPP_URL = STACK_CONFIG.webAppUrl;
|
||||
const STACK_GRAPHQL_URL = STACK_CONFIG.graphqlUrl;
|
||||
|
||||
async function fetchPositions(request: APIRequestContext, owner: string) {
|
||||
const response = await request.post(STACK_GRAPHQL_URL, {
|
||||
data: {
|
||||
query: `
|
||||
query PositionsByOwner($owner: String!) {
|
||||
positionss(where: { owner: $owner }, limit: 100) {
|
||||
items {
|
||||
id
|
||||
owner
|
||||
taxRate
|
||||
stakeDeposit
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: { owner },
|
||||
},
|
||||
headers: { 'content-type': 'application/json' },
|
||||
});
|
||||
|
||||
expect(response.ok()).toBeTruthy();
|
||||
const payload = await response.json();
|
||||
return (payload?.data?.positionss?.items ?? []) as Array<{
|
||||
id: string;
|
||||
owner: string;
|
||||
taxRate: number;
|
||||
stakeDeposit: string;
|
||||
status: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
async function fetchStats(request: APIRequestContext) {
|
||||
const response = await request.post(STACK_GRAPHQL_URL, {
|
||||
data: {
|
||||
query: `
|
||||
query Stats {
|
||||
stats(id: "0x01") {
|
||||
kraikenTotalSupply
|
||||
kraikenStakedSupply
|
||||
percentageStaked
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
headers: { 'content-type': 'application/json' },
|
||||
});
|
||||
|
||||
expect(response.ok()).toBeTruthy();
|
||||
const payload = await response.json();
|
||||
return payload?.data?.stats;
|
||||
}
|
||||
|
||||
test.describe('Max Stake All Tax Rates', () => {
|
||||
test.beforeAll(async () => {
|
||||
await validateStackHealthy(STACK_CONFIG);
|
||||
});
|
||||
|
||||
test('fills all tax rates until maxStake is reached', async ({ browser, request }) => {
|
||||
console.log('[TEST] Creating wallet context...');
|
||||
const context = await createWalletContext(browser, {
|
||||
privateKey: ACCOUNT_PRIVATE_KEY,
|
||||
rpcUrl: STACK_RPC_URL,
|
||||
});
|
||||
|
||||
const page = await context.newPage();
|
||||
|
||||
// Log browser console messages
|
||||
page.on('console', msg => console.log(`[BROWSER] ${msg.type()}: ${msg.text()}`));
|
||||
page.on('pageerror', error => console.log(`[BROWSER ERROR] ${error.message}`));
|
||||
|
||||
try {
|
||||
console.log('[TEST] Loading app...');
|
||||
await page.goto(`${STACK_WEBAPP_URL}/app/`, { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForTimeout(3_000);
|
||||
|
||||
// Verify wallet connection
|
||||
console.log('[TEST] Checking for wallet display...');
|
||||
const walletDisplay = page.getByText(/0xf39F/i).first();
|
||||
await expect(walletDisplay).toBeVisible({ timeout: 15_000 });
|
||||
console.log('[TEST] Wallet connected successfully!');
|
||||
|
||||
// Step 1: Mint test ETH
|
||||
console.log('[TEST] Navigating to cheats page...');
|
||||
await page.goto(`${STACK_WEBAPP_URL}/app/#/cheats`);
|
||||
await expect(page.getByRole('heading', { name: 'Cheat Console' })).toBeVisible();
|
||||
|
||||
console.log('[TEST] Minting test ETH (10 ETH)...');
|
||||
await page.getByLabel('RPC URL').fill(STACK_RPC_URL);
|
||||
await page.getByLabel('Recipient').fill(ACCOUNT_ADDRESS);
|
||||
const mintButton = page.getByRole('button', { name: 'Mint' });
|
||||
await expect(mintButton).toBeEnabled();
|
||||
await mintButton.click();
|
||||
await page.waitForTimeout(3_000);
|
||||
|
||||
// Step 2: Buy a large amount of KRK tokens
|
||||
console.log('[TEST] Buying KRK tokens (swapping 5 ETH)...');
|
||||
const ethToSpendInput = page.getByLabel('ETH to spend');
|
||||
await ethToSpendInput.fill('5');
|
||||
|
||||
const buyButton = page.getByRole('button', { name: 'Buy' }).last();
|
||||
await expect(buyButton).toBeVisible();
|
||||
await buyButton.click();
|
||||
|
||||
// Wait for swap to complete
|
||||
console.log('[TEST] Waiting for swap to process...');
|
||||
try {
|
||||
await page.getByRole('button', { name: /Submitting/i }).waitFor({ state: 'visible', timeout: 5_000 });
|
||||
await page.getByRole('button', { name: 'Buy' }).last().waitFor({ state: 'visible', timeout: 60_000 });
|
||||
console.log('[TEST] Swap completed!');
|
||||
} catch (e) {
|
||||
console.log('[TEST] Swap may have completed instantly');
|
||||
}
|
||||
await page.waitForTimeout(2_000);
|
||||
|
||||
// Verify we have KRK tokens
|
||||
console.log('[TEST] Verifying KRK balance via RPC...');
|
||||
const balanceResponse = await fetch(STACK_RPC_URL, {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: 'eth_call',
|
||||
params: [{
|
||||
to: '0xe527ddac2592faa45884a0b78e4d377a5d3df8cc', // KRK token
|
||||
data: `0x70a08231000000000000000000000000${ACCOUNT_ADDRESS.slice(2)}` // balanceOf(address)
|
||||
}, 'latest']
|
||||
})
|
||||
});
|
||||
|
||||
const balanceData = await balanceResponse.json();
|
||||
const balance = BigInt(balanceData.result || '0');
|
||||
console.log(`[TEST] KRK balance: ${balance.toString()} wei`);
|
||||
expect(balance).toBeGreaterThan(0n);
|
||||
|
||||
// Step 3: Navigate to stake page
|
||||
console.log('[TEST] Navigating to stake page...');
|
||||
await page.goto(`${STACK_WEBAPP_URL}/app/#/stake`);
|
||||
await page.waitForTimeout(2_000);
|
||||
|
||||
const tokenAmountSlider = page.getByRole('slider', { name: 'Token Amount' });
|
||||
await expect(tokenAmountSlider).toBeVisible({ timeout: 15_000 });
|
||||
|
||||
// Step 4: Create staking positions for all tax rates
|
||||
console.log(`[TEST] Creating positions for all ${TAX_RATE_OPTIONS.length} tax rates...`);
|
||||
|
||||
let positionCount = 0;
|
||||
let maxStakeReached = false;
|
||||
|
||||
// We'll try to create positions with increasing amounts to fill maxStake faster
|
||||
const baseStakeAmount = 1000;
|
||||
|
||||
for (const taxRateOption of TAX_RATE_OPTIONS) {
|
||||
if (maxStakeReached) break;
|
||||
|
||||
console.log(`[TEST] Creating position with tax rate ${taxRateOption.index} (${taxRateOption.year}% annually)...`);
|
||||
|
||||
// Fill stake form
|
||||
const stakeAmountInput = page.getByLabel('Staking Amount');
|
||||
await expect(stakeAmountInput).toBeVisible({ timeout: 10_000 });
|
||||
await stakeAmountInput.fill(baseStakeAmount.toString());
|
||||
|
||||
const taxSelect = page.getByRole('combobox', { name: 'Tax' });
|
||||
await taxSelect.selectOption({ value: taxRateOption.index.toString() });
|
||||
|
||||
// Click stake button
|
||||
const stakeButton = page.getByRole('main').getByRole('button', { name: /Stake|Snatch and Stake/i });
|
||||
await expect(stakeButton).toBeVisible({ timeout: 5_000 });
|
||||
|
||||
// Check if staking is still possible (button might be disabled if maxStake reached)
|
||||
const isDisabled = await stakeButton.isDisabled();
|
||||
if (isDisabled) {
|
||||
console.log('[TEST] Stake button is disabled - likely maxStake reached');
|
||||
maxStakeReached = true;
|
||||
break;
|
||||
}
|
||||
|
||||
await stakeButton.click();
|
||||
|
||||
// Wait for transaction to process
|
||||
try {
|
||||
await page.getByRole('button', { name: /Sign Transaction|Waiting/i }).waitFor({ state: 'visible', timeout: 5_000 });
|
||||
await page.getByRole('button', { name: /Stake|Snatch and Stake/i }).waitFor({ state: 'visible', timeout: 60_000 });
|
||||
} catch (e) {
|
||||
// Transaction completed instantly or failed
|
||||
// Check if we got an error message
|
||||
const errorVisible = await page.getByText(/error|failed|exceeded/i).isVisible().catch(() => false);
|
||||
if (errorVisible) {
|
||||
console.log('[TEST] Transaction failed - likely maxStake reached');
|
||||
maxStakeReached = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
positionCount++;
|
||||
await page.waitForTimeout(2_000);
|
||||
}
|
||||
|
||||
console.log(`[TEST] Created ${positionCount} positions`);
|
||||
|
||||
// Step 5: Verify positions via GraphQL
|
||||
console.log('[TEST] Verifying positions via GraphQL...');
|
||||
const positions = await fetchPositions(request, ACCOUNT_ADDRESS);
|
||||
console.log(`[TEST] Found ${positions.length} position(s) in GraphQL`);
|
||||
|
||||
const activePositions = positions.filter(p => p.status === 'Active');
|
||||
console.log(`[TEST] ${activePositions.length} active positions`);
|
||||
|
||||
expect(activePositions.length).toBeGreaterThan(0);
|
||||
|
||||
// Verify we have positions with different tax rates
|
||||
const uniqueTaxRates = new Set(activePositions.map(p => p.taxRate));
|
||||
console.log(`[TEST] Unique tax rates used: ${uniqueTaxRates.size}`);
|
||||
|
||||
// We should have created positions for most/all tax rates (may have pre-existing positions from other tests)
|
||||
expect(positionCount).toBeGreaterThan(20);
|
||||
expect(uniqueTaxRates.size).toBeGreaterThan(20);
|
||||
|
||||
// Step 6: Verify maxStake constraint
|
||||
console.log('[TEST] Verifying maxStake constraint...');
|
||||
const stats = await fetchStats(request);
|
||||
console.log(`[TEST] Staked percentage: ${stats?.percentageStaked}`);
|
||||
|
||||
if (stats?.percentageStaked) {
|
||||
const percentageStaked = parseFloat(stats.percentageStaked);
|
||||
// percentageStaked is a ratio (0-1), maxStake is 20%
|
||||
expect(percentageStaked).toBeLessThanOrEqual(1.0);
|
||||
console.log(`[TEST] ✅ MaxStake constraint respected: ${(percentageStaked * 100).toFixed(2)}% staked`);
|
||||
}
|
||||
|
||||
console.log(`[TEST] ✅ Test complete: Created ${activePositions.length} positions across ${uniqueTaxRates.size} different tax rates`);
|
||||
|
||||
// Take screenshot of final stake page with all positions
|
||||
console.log('[TEST] Taking screenshot of stake page...');
|
||||
await page.screenshot({ path: 'test-results/stake-page-with-all-positions.png', fullPage: true });
|
||||
console.log('[TEST] Screenshot saved to test-results/stake-page-with-all-positions.png');
|
||||
} finally {
|
||||
await context.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
125
tests/e2e/03-verify-graphql-url.spec.ts
Normal file
125
tests/e2e/03-verify-graphql-url.spec.ts
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { Wallet } from 'ethers';
|
||||
import { createWalletContext } from '../setup/wallet-provider';
|
||||
import { getStackConfig, validateStackHealthy } from '../setup/stack';
|
||||
|
||||
const ACCOUNT_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
|
||||
const STACK_CONFIG = getStackConfig();
|
||||
const STACK_RPC_URL = STACK_CONFIG.rpcUrl;
|
||||
const STACK_WEBAPP_URL = STACK_CONFIG.webAppUrl;
|
||||
const STACK_GRAPHQL_URL = STACK_CONFIG.graphqlUrl;
|
||||
|
||||
test.describe('GraphQL URL Verification', () => {
|
||||
test.beforeAll(async () => {
|
||||
await validateStackHealthy(STACK_CONFIG);
|
||||
});
|
||||
|
||||
test('should load staking page without errors and use correct GraphQL endpoint', async ({ browser }) => {
|
||||
console.log('[TEST] Creating wallet context...');
|
||||
const context = await createWalletContext(browser, {
|
||||
privateKey: ACCOUNT_PRIVATE_KEY,
|
||||
rpcUrl: STACK_RPC_URL,
|
||||
});
|
||||
|
||||
const page = await context.newPage();
|
||||
|
||||
const consoleErrors: string[] = [];
|
||||
const consoleWarnings: string[] = [];
|
||||
const consoleLogs: string[] = [];
|
||||
const networkRequests: Array<{ url: string; status: number }> = [];
|
||||
const allNetworkActivity: Array<{ url: string; status: number }> = [];
|
||||
|
||||
// Capture all console messages
|
||||
page.on('console', msg => {
|
||||
const text = msg.text();
|
||||
if (msg.type() === 'error') {
|
||||
consoleErrors.push(text);
|
||||
} else if (msg.type() === 'warning') {
|
||||
consoleWarnings.push(text);
|
||||
} else if (text.includes('load') || text.includes('graphql') || text.includes('chain') || text.includes('DEBUG')) {
|
||||
consoleLogs.push(text);
|
||||
}
|
||||
});
|
||||
|
||||
// Capture all network requests
|
||||
page.on('response', response => {
|
||||
const url = response.url();
|
||||
const status = response.status();
|
||||
|
||||
allNetworkActivity.push({ url, status });
|
||||
|
||||
if (url.includes('graphql')) {
|
||||
networkRequests.push({ url, status });
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
console.log('[TEST] Navigating to staking page...');
|
||||
await page.goto(`${STACK_WEBAPP_URL}/app/#/stake`, { waitUntil: 'domcontentloaded' });
|
||||
|
||||
// Wait for page to fully load and settle
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Give more time for Vue components to mount and composables to initialize
|
||||
console.log('[TEST] Waiting for composables to initialize...');
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
// Log findings
|
||||
console.log('\n=== Console Errors ===');
|
||||
if (consoleErrors.length === 0) {
|
||||
console.log('✅ No console errors');
|
||||
} else {
|
||||
console.log('❌ Found console errors:');
|
||||
consoleErrors.forEach(err => console.log(` - ${err}`));
|
||||
}
|
||||
|
||||
console.log('\n=== Console Warnings ===');
|
||||
if (consoleWarnings.length > 0) {
|
||||
consoleWarnings.slice(0, 5).forEach(warn => console.log(` - ${warn}`));
|
||||
}
|
||||
|
||||
console.log('\n=== Relevant Console Logs ===');
|
||||
if (consoleLogs.length > 0) {
|
||||
consoleLogs.forEach(log => console.log(` - ${log}`));
|
||||
}
|
||||
|
||||
console.log('\n=== GraphQL Requests ===');
|
||||
if (networkRequests.length === 0) {
|
||||
console.log('⚠️ No GraphQL requests detected');
|
||||
} else {
|
||||
networkRequests.forEach(req => {
|
||||
const isCorrect = req.url === STACK_GRAPHQL_URL;
|
||||
const icon = isCorrect ? '✅' : '❌';
|
||||
console.log(`${icon} ${req.url} (Status: ${req.status})`);
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\n=== Sample Network Activity ===');
|
||||
allNetworkActivity.slice(0, 10).forEach(req => {
|
||||
console.log(` ${req.status} ${req.url}`);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
const incorrectRequests = networkRequests.filter(
|
||||
req => req.url.includes('/app/graphql')
|
||||
);
|
||||
|
||||
// No console errors
|
||||
expect(consoleErrors.length).toBe(0);
|
||||
|
||||
// No requests to /app/graphql
|
||||
expect(incorrectRequests.length).toBe(0);
|
||||
|
||||
// If there were GraphQL requests, they should go to the correct endpoint
|
||||
if (networkRequests.length > 0) {
|
||||
const correctRequests = networkRequests.filter(req => req.url === STACK_GRAPHQL_URL);
|
||||
expect(correctRequests.length).toBeGreaterThan(0);
|
||||
} else {
|
||||
console.log('\n⚠️ WARNING: No GraphQL requests detected - composables may not be initializing');
|
||||
}
|
||||
} finally {
|
||||
await page.close();
|
||||
await context.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -2,9 +2,9 @@ import deploymentsLocal from '../../onchain/deployments-local.json';
|
|||
|
||||
const env = import.meta.env;
|
||||
|
||||
const LOCAL_PONDER_URL = env.VITE_PONDER_BASE_SEPOLIA_LOCAL_FORK ?? '/api/graphql';
|
||||
const LOCAL_TXNBOT_URL = env.VITE_TXNBOT_BASE_SEPOLIA_LOCAL_FORK ?? '/api/txn';
|
||||
const LOCAL_RPC_URL = env.VITE_LOCAL_RPC_URL ?? '/api/rpc';
|
||||
const LOCAL_PONDER_PATH = '/api/graphql';
|
||||
const LOCAL_TXNBOT_PATH = '/api/txn';
|
||||
const LOCAL_RPC_PATH = '/api/rpc';
|
||||
|
||||
interface DeploymentContracts {
|
||||
Kraiken?: string;
|
||||
|
|
@ -45,11 +45,28 @@ function detectDefaultChainId(): number {
|
|||
|
||||
export const DEFAULT_CHAIN_ID = detectDefaultChainId();
|
||||
|
||||
function resolveLocalEndpoint(value: string | undefined, fallback: string): string {
|
||||
const candidate = (value ?? fallback).trim();
|
||||
if (!candidate) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (candidate.startsWith('http://') || candidate.startsWith('https://')) {
|
||||
return candidate;
|
||||
}
|
||||
|
||||
return candidate.startsWith('/') ? candidate : `/${candidate}`;
|
||||
}
|
||||
|
||||
const LOCAL_GRAPHQL_ENDPOINT = resolveLocalEndpoint(env.VITE_PONDER_BASE_SEPOLIA_LOCAL_FORK, LOCAL_PONDER_PATH);
|
||||
const LOCAL_TXNBOT_ENDPOINT = resolveLocalEndpoint(env.VITE_TXNBOT_BASE_SEPOLIA_LOCAL_FORK, LOCAL_TXNBOT_PATH);
|
||||
const LOCAL_RPC_ENDPOINT = resolveLocalEndpoint(env.VITE_LOCAL_RPC_URL, LOCAL_RPC_PATH);
|
||||
|
||||
export const chainsData = [
|
||||
{
|
||||
// local base sepolia fork
|
||||
id: 31337,
|
||||
graphql: LOCAL_PONDER_URL,
|
||||
graphql: LOCAL_GRAPHQL_ENDPOINT,
|
||||
path: 'local',
|
||||
stake: LOCAL_STAKE,
|
||||
harb: LOCAL_KRAIKEN,
|
||||
|
|
@ -58,14 +75,14 @@ export const chainsData = [
|
|||
weth: LOCAL_WETH,
|
||||
swapRouter: LOCAL_ROUTER,
|
||||
liquidityManager: LOCAL_LM,
|
||||
txnBot: LOCAL_TXNBOT_URL,
|
||||
rpc: LOCAL_RPC_URL,
|
||||
txnBot: LOCAL_TXNBOT_ENDPOINT,
|
||||
rpc: LOCAL_RPC_ENDPOINT,
|
||||
},
|
||||
},
|
||||
{
|
||||
// sepolia
|
||||
id: 11155111,
|
||||
graphql: import.meta.env.VITE_PONDER_SEPOLIA ?? '',
|
||||
graphql: env.VITE_PONDER_SEPOLIA ?? '',
|
||||
path: 'sepolia',
|
||||
stake: '0xCd21a41a137BCAf8743E47D048F57D92398f7Da9',
|
||||
harb: '0x087F256D11fe533b0c7d372e44Ee0F9e47C89dF9',
|
||||
|
|
@ -75,7 +92,7 @@ export const chainsData = [
|
|||
{
|
||||
// base-sepolia (local dev default)
|
||||
id: 84532,
|
||||
graphql: import.meta.env.VITE_PONDER_BASE_SEPOLIA_LOCAL_FORK ?? LOCAL_PONDER_URL,
|
||||
graphql: LOCAL_GRAPHQL_ENDPOINT,
|
||||
path: 'sepoliabase',
|
||||
stake: '0xe28020BCdEeAf2779dd47c670A8eFC2973316EE2',
|
||||
harb: '0x22c264Ecf8D4E49D1E3CabD8DD39b7C4Ab51C1B8',
|
||||
|
|
@ -83,13 +100,13 @@ export const chainsData = [
|
|||
cheats: {
|
||||
weth: '0x4200000000000000000000000000000000000006',
|
||||
swapRouter: '0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4',
|
||||
txnBot: import.meta.env.VITE_TXNBOT_BASE_SEPOLIA_LOCAL_FORK ?? LOCAL_TXNBOT_URL,
|
||||
txnBot: LOCAL_TXNBOT_ENDPOINT,
|
||||
},
|
||||
},
|
||||
{
|
||||
// base mainnet
|
||||
id: 8453,
|
||||
graphql: import.meta.env.VITE_PONDER_BASE ?? '',
|
||||
graphql: env.VITE_PONDER_BASE ?? '',
|
||||
path: 'base',
|
||||
stake: '0xed70707fab05d973ad41eae8d17e2bcd36192cfc',
|
||||
harb: '0x45caa5929f6ee038039984205bdecf968b954820',
|
||||
|
|
@ -97,7 +114,7 @@ export const chainsData = [
|
|||
cheats: {
|
||||
weth: '0x4200000000000000000000000000000000000006',
|
||||
swapRouter: '',
|
||||
txnBot: import.meta.env.VITE_TXNBOT_BASE ?? '',
|
||||
txnBot: env.VITE_TXNBOT_BASE ?? '',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -27,8 +27,11 @@ class ChainConfigService {
|
|||
if (!normalized) {
|
||||
throw new Error(`${label} endpoint not configured for chain ${chainId}.`);
|
||||
}
|
||||
if (normalized.startsWith('http://') || normalized.startsWith('https://')) {
|
||||
return normalized;
|
||||
}
|
||||
return normalized.startsWith('/') ? normalized : `/${normalized}`;
|
||||
}
|
||||
}
|
||||
|
||||
function assertNever(_x: never): never {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue