Some checks failed
Build and Deploy / build (push) Has been cancelled
- Add RybbitService for tracking e-commerce events - Update useAnalytics hook to track with both OpenPanel and Rybbit - Add Rybbit script to layout for page view tracking - Track all applicable store events: product views, cart, checkout, orders, search, etc.
255 lines
8.8 KiB
JavaScript
255 lines
8.8 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Complete API test simulating frontend checkout flow
|
|
* Tests every step the frontend takes
|
|
*/
|
|
|
|
const SALEOR_API_URL = 'https://api.manoonoils.com/graphql/';
|
|
|
|
async function saleorFetch(query, variables = {}) {
|
|
const response = await fetch(SALEOR_API_URL, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ query: query.replace(/\n\s*/g, ' '), variables }),
|
|
});
|
|
const result = await response.json();
|
|
if (result.errors) {
|
|
console.error('GraphQL Error:', JSON.stringify(result.errors, null, 2));
|
|
throw new Error(result.errors[0].message);
|
|
}
|
|
return result.data;
|
|
}
|
|
|
|
async function runTest() {
|
|
console.log('🧪 TESTING FRONTEND CHECKOUT FLOW\n');
|
|
console.log('=' .repeat(50));
|
|
|
|
let checkoutId = null;
|
|
let checkoutToken = null;
|
|
let shippingMethodId = null;
|
|
|
|
try {
|
|
// STEP 1: Create checkout (like frontend does on first cart add)
|
|
console.log('\n📦 STEP 1: Create Checkout');
|
|
console.log('-'.repeat(50));
|
|
|
|
const createResult = await saleorFetch(`
|
|
mutation CheckoutCreate($input: CheckoutCreateInput!) {
|
|
checkoutCreate(input: $input) {
|
|
checkout {
|
|
id
|
|
token
|
|
totalPrice { gross { amount currency } }
|
|
subtotalPrice { gross { amount } }
|
|
}
|
|
errors { field message }
|
|
}
|
|
}
|
|
`, {
|
|
input: {
|
|
channel: "default-channel",
|
|
email: "test@test.com",
|
|
lines: [],
|
|
languageCode: "SR"
|
|
}
|
|
});
|
|
|
|
checkoutId = createResult.checkoutCreate.checkout.id;
|
|
checkoutToken = createResult.checkoutCreate.checkout.token;
|
|
|
|
console.log('✅ Checkout created');
|
|
console.log(' ID:', checkoutId);
|
|
console.log(' Token:', checkoutToken);
|
|
console.log(' Initial Total:', createResult.checkoutCreate.checkout.totalPrice.gross.amount, 'RSD');
|
|
|
|
// STEP 2: Add product (like frontend does)
|
|
console.log('\n🛒 STEP 2: Add Product to Cart');
|
|
console.log('-'.repeat(50));
|
|
|
|
// Get a valid variant first
|
|
const productsResult = await saleorFetch(`
|
|
query {
|
|
products(channel: "default-channel", first: 1) {
|
|
edges {
|
|
node {
|
|
variants { id name }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`);
|
|
|
|
const variantId = productsResult.products.edges[0].node.variants[0].id;
|
|
|
|
const addLineResult = await saleorFetch(`
|
|
mutation CheckoutLinesAdd($checkoutId: ID!, $lines: [CheckoutLineInput!]!) {
|
|
checkoutLinesAdd(checkoutId: $checkoutId, lines: $lines) {
|
|
checkout {
|
|
id
|
|
token
|
|
totalPrice { gross { amount currency } }
|
|
subtotalPrice { gross { amount } }
|
|
}
|
|
errors { field message }
|
|
}
|
|
}
|
|
`, {
|
|
checkoutId: checkoutId,
|
|
lines: [{ variantId: variantId, quantity: 1 }]
|
|
});
|
|
|
|
const afterAdd = addLineResult.checkoutLinesAdd.checkout;
|
|
console.log('✅ Product added');
|
|
console.log(' Product Total:', afterAdd.totalPrice.gross.amount, 'RSD');
|
|
console.log(' Subtotal:', afterAdd.subtotalPrice.gross.amount, 'RSD');
|
|
|
|
// STEP 3: Refresh checkout by token (what refreshCheckout() does)
|
|
console.log('\n🔄 STEP 3: Refresh Checkout by Token');
|
|
console.log('-'.repeat(50));
|
|
console.log(' (This simulates what refreshCheckout() does in the store)');
|
|
|
|
const refreshResult = await saleorFetch(`
|
|
query GetCheckout($token: UUID!) {
|
|
checkout(token: $token) {
|
|
id
|
|
token
|
|
totalPrice { gross { amount currency } }
|
|
subtotalPrice { gross { amount } }
|
|
}
|
|
}
|
|
`, { token: checkoutToken });
|
|
|
|
console.log('✅ Refreshed checkout');
|
|
console.log(' Total from refresh:', refreshResult.checkout.totalPrice.gross.amount, 'RSD');
|
|
|
|
// STEP 4: Set shipping address
|
|
console.log('\n📍 STEP 4: Set Shipping Address');
|
|
console.log('-'.repeat(50));
|
|
|
|
const addressResult = await saleorFetch(`
|
|
mutation CheckoutShippingAddressUpdate($checkoutId: ID!, $shippingAddress: AddressInput!) {
|
|
checkoutShippingAddressUpdate(checkoutId: $checkoutId, shippingAddress: $shippingAddress) {
|
|
checkout {
|
|
id
|
|
shippingMethods { id name price { amount currency } }
|
|
}
|
|
errors { field message }
|
|
}
|
|
}
|
|
`, {
|
|
checkoutId: checkoutId,
|
|
shippingAddress: {
|
|
firstName: "Test",
|
|
lastName: "User",
|
|
streetAddress1: "123 Test Street",
|
|
city: "Belgrade",
|
|
postalCode: "11000",
|
|
country: "RS",
|
|
phone: "+38160123456"
|
|
}
|
|
});
|
|
|
|
const methods = addressResult.checkoutShippingAddressUpdate.checkout.shippingMethods;
|
|
console.log('✅ Address set');
|
|
console.log(' Available shipping methods:', methods.length);
|
|
|
|
if (methods.length === 0) {
|
|
console.log('❌ No shipping methods available!');
|
|
return;
|
|
}
|
|
|
|
methods.forEach((m, i) => {
|
|
console.log(` [${i+1}] ${m.name}: ${m.price.amount} ${m.price.currency}`);
|
|
});
|
|
|
|
shippingMethodId = methods[0].id;
|
|
const shippingPrice = methods[0].price.amount;
|
|
|
|
// STEP 5: Select shipping method (what happens when user clicks radio button)
|
|
console.log('\n🚚 STEP 5: Select Shipping Method');
|
|
console.log('-'.repeat(50));
|
|
console.log(` Selecting: ${methods[0].name} (${shippingPrice} RSD)`);
|
|
|
|
const methodResult = await saleorFetch(`
|
|
mutation CheckoutShippingMethodUpdate($checkoutId: ID!, $shippingMethodId: ID!) {
|
|
checkoutShippingMethodUpdate(checkoutId: $checkoutId, shippingMethodId: $shippingMethodId) {
|
|
checkout {
|
|
id
|
|
totalPrice { gross { amount currency } }
|
|
subtotalPrice { gross { amount } }
|
|
shippingPrice { gross { amount } }
|
|
}
|
|
errors { field message }
|
|
}
|
|
}
|
|
`, {
|
|
checkoutId: checkoutId,
|
|
shippingMethodId: shippingMethodId
|
|
});
|
|
|
|
const afterMethod = methodResult.checkoutShippingMethodUpdate.checkout;
|
|
console.log('✅ Shipping method set');
|
|
console.log(' Total:', afterMethod.totalPrice.gross.amount, 'RSD');
|
|
console.log(' Subtotal:', afterMethod.subtotalPrice.gross.amount, 'RSD');
|
|
console.log(' Shipping:', afterMethod.shippingPrice.gross.amount, 'RSD');
|
|
|
|
// STEP 6: Refresh checkout again (what refreshCheckout() does after setting method)
|
|
console.log('\n🔄 STEP 6: Refresh Checkout Again');
|
|
console.log('-'.repeat(50));
|
|
console.log(' (Simulating refreshCheckout() call in handleShippingMethodSelect)');
|
|
|
|
const finalRefresh = await saleorFetch(`
|
|
query GetCheckout($token: UUID!) {
|
|
checkout(token: $token) {
|
|
id
|
|
token
|
|
totalPrice { gross { amount currency } }
|
|
subtotalPrice { gross { amount } }
|
|
shippingPrice { gross { amount } }
|
|
}
|
|
}
|
|
`, { token: checkoutToken });
|
|
|
|
const final = finalRefresh.checkout;
|
|
console.log('✅ Final checkout state after refresh:');
|
|
console.log(' Total:', final.totalPrice.gross.amount, 'RSD');
|
|
console.log(' Subtotal:', final.subtotalPrice.gross.amount, 'RSD');
|
|
console.log(' Shipping:', final.shippingPrice.gross.amount, 'RSD');
|
|
|
|
// VERIFICATION
|
|
console.log('\n📊 VERIFICATION');
|
|
console.log('=' .repeat(50));
|
|
const expectedTotal = final.subtotalPrice.gross.amount + final.shippingPrice.gross.amount;
|
|
const actualTotal = final.totalPrice.gross.amount;
|
|
|
|
if (actualTotal === expectedTotal) {
|
|
console.log('✅ PASS: API returns correct total with shipping');
|
|
console.log(` ${final.subtotalPrice.gross.amount} + ${final.shippingPrice.gross.amount} = ${actualTotal}`);
|
|
} else {
|
|
console.log('❌ FAIL: API total does not include shipping');
|
|
console.log(` Expected: ${expectedTotal}, Got: ${actualTotal}`);
|
|
}
|
|
|
|
console.log('\n🔍 FRONTEND ISSUE ANALYSIS');
|
|
console.log('=' .repeat(50));
|
|
console.log('The API works correctly. The bug is in the frontend.');
|
|
console.log('');
|
|
console.log('What should happen:');
|
|
console.log(' 1. User selects shipping method → handleShippingMethodSelect()');
|
|
console.log(' 2. Calls checkoutService.updateShippingMethod() → API updates');
|
|
console.log(' 3. Calls refreshCheckout() → store updates with new checkout');
|
|
console.log(' 4. Component re-renders with new checkout.totalPrice');
|
|
console.log('');
|
|
console.log('Check browser console for:');
|
|
console.log(' - [Checkout Debug] logs showing totalPrice values');
|
|
console.log(' - Network tab showing the GraphQL mutation/refresh calls');
|
|
console.log(' - React DevTools showing if checkout object updates');
|
|
|
|
} catch (error) {
|
|
console.error('\n❌ Test failed:', error.message);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
runTest();
|