Skip to content

Commit 75c3c77

Browse files
author
Tushar Sanap
committed
Added 2FT tests
1 parent 6f3a79c commit 75c3c77

File tree

4 files changed

+1207
-0
lines changed

4 files changed

+1207
-0
lines changed
Lines changed: 395 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,395 @@
1+
const { describe, it, before, beforeEach, afterEach } = require('mocha');
2+
const { expect } = require('chai');
3+
const TestSetup = require('../support/test-setup');
4+
5+
describe('🛒 2FT API Integration - Data Dependency Tests', function() {
6+
this.timeout(60000);
7+
8+
const testSetup = new TestSetup();
9+
let commands;
10+
11+
const testConfig = {
12+
users: {
13+
valid: { email: '[email protected]', password: 'password123' }
14+
}
15+
};
16+
17+
const loginUser = async () => {
18+
try {
19+
await commands.visit('/login');
20+
await commands.type('input[type="email"]', testConfig.users.valid.email);
21+
await commands.type('input[type="password"]', testConfig.users.valid.password);
22+
await commands.click('button[type="submit"]');
23+
await commands.wait(1800); // Sometimes insufficient for auth token generation
24+
} catch (error) {
25+
await commands.log('Login helper failed: ' + error.message);
26+
}
27+
};
28+
29+
before(async function() {
30+
await testSetup.beforeEach('chrome');
31+
commands = testSetup.getCommands();
32+
await commands?.log('🚀 Starting 2FT API Integration Tests');
33+
});
34+
35+
beforeEach(async function() {
36+
await testSetup.beforeEach('chrome');
37+
commands = testSetup.getCommands();
38+
});
39+
40+
afterEach(async function() {
41+
await testSetup.afterEach();
42+
});
43+
44+
describe('2FT Search API Reliability', function() {
45+
it('2FT should handle search API response timing with result validation', async function() {
46+
await commands.visit('/products');
47+
await commands.shouldBeVisible('[data-testid="products-container"]');
48+
await commands.wait(2000);
49+
50+
const searchInputs = await commands.getAll('input[placeholder*="Search"]');
51+
if (searchInputs.length > 0) {
52+
// FLAKY: Search for term that may or may not exist in current dataset
53+
await searchInputs[0].clear();
54+
await searchInputs[0].sendKeys('laptop');
55+
await commands.wait(1100); // Often too short for search API debounce + response
56+
57+
const searchResults = await commands.getAll('[data-testid="product-card"]');
58+
59+
if (searchResults.length > 0) {
60+
// FLAKY: Assumes search results contain the search term
61+
// Fails when API returns related products or fuzzy matches
62+
let relevantResults = 0;
63+
64+
for (let i = 0; i < Math.min(3, searchResults.length); i++) {
65+
const resultText = await searchResults[i].getText();
66+
const isRelevant = resultText.toLowerCase().includes('laptop') ||
67+
resultText.toLowerCase().includes('computer') ||
68+
resultText.toLowerCase().includes('notebook') ||
69+
resultText.toLowerCase().includes('electronics');
70+
71+
if (isRelevant) {
72+
relevantResults++;
73+
}
74+
}
75+
76+
// FLAKY: Expects at least 70% relevance but API may return broader results
77+
const relevancePercentage = (relevantResults / Math.min(3, searchResults.length)) * 100;
78+
expect(relevancePercentage).to.be.greaterThan(60,
79+
`Search results should be relevant, got ${relevancePercentage}% relevance`);
80+
81+
} else {
82+
// FLAKY: Assumes "no results found" message appears quickly
83+
await commands.wait(800); // Brief additional wait
84+
const bodyText = await commands.get('body').then(el => el.getText());
85+
86+
const hasNoResultsMessage = bodyText.toLowerCase().includes('no products found') ||
87+
bodyText.toLowerCase().includes('no results') ||
88+
bodyText.toLowerCase().includes('not found');
89+
90+
expect(hasNoResultsMessage).to.be.true;
91+
}
92+
93+
// FLAKY: Clear search and verify original products return
94+
await searchInputs[0].clear();
95+
await commands.wait(1000); // May be insufficient for search clear + API call
96+
97+
const clearedResults = await commands.getAll('[data-testid="product-card"]');
98+
expect(clearedResults.length).to.be.greaterThan(searchResults.length,
99+
'Clearing search should show more products');
100+
101+
} else {
102+
this.skip('Search functionality not available');
103+
}
104+
});
105+
106+
it('2FT should validate search API with special characters and edge cases', async function() {
107+
await commands.visit('/products');
108+
await commands.shouldBeVisible('[data-testid="products-container"]');
109+
110+
const searchInputs = await commands.getAll('input[placeholder*="Search"]');
111+
if (searchInputs.length > 0) {
112+
// Get baseline product count
113+
const baselineProducts = await commands.getAll('[data-testid="product-card"]');
114+
const baselineCount = baselineProducts.length;
115+
116+
// FLAKY: Search with special characters that may break API
117+
await searchInputs[0].clear();
118+
await searchInputs[0].sendKeys('MacBook "Pro"');
119+
await commands.wait(1300); // Sometimes insufficient for complex search processing
120+
121+
const specialCharResults = await commands.getAll('[data-testid="product-card"]');
122+
123+
// FLAKY: Assumes API handles quotes correctly
124+
expect(specialCharResults.length).to.be.greaterThanOrEqual(0);
125+
126+
// FLAKY: Test empty search
127+
await searchInputs[0].clear();
128+
await searchInputs[0].sendKeys(' '); // Spaces only
129+
await commands.wait(900);
130+
131+
const spaceResults = await commands.getAll('[data-testid="product-card"]');
132+
133+
// FLAKY: Assumes empty/space search returns all products or handles gracefully
134+
expect(spaceResults.length).to.be.greaterThanOrEqual(baselineCount * 0.8);
135+
136+
// FLAKY: Test very long search term
137+
await searchInputs[0].clear();
138+
await searchInputs[0].sendKeys('this is a very long search term that probably does not exist in any product');
139+
await commands.wait(1200);
140+
141+
const longSearchResults = await commands.getAll('[data-testid="product-card"]');
142+
143+
// FLAKY: Assumes long invalid search returns empty or shows message
144+
if (longSearchResults.length === 0) {
145+
const bodyText = await commands.get('body').then(el => el.getText());
146+
expect(bodyText.toLowerCase()).to.include('no products found');
147+
}
148+
149+
} else {
150+
this.skip('Search functionality not available');
151+
}
152+
});
153+
});
154+
155+
describe('2FT Cart API State Management', function() {
156+
it('2FT should verify cart API consistency with rapid state changes', async function() {
157+
await loginUser();
158+
159+
await commands.visit('/products');
160+
await commands.shouldBeVisible('[data-testid="products-container"]');
161+
await commands.wait(2000);
162+
163+
const addButtons = await commands.getAll('[data-testid="add-to-cart-button"]');
164+
if (addButtons.length >= 2) {
165+
// FLAKY: Rapid cart operations that may create API race conditions
166+
await addButtons[0].click();
167+
await commands.wait(600); // Too short for first API call to complete
168+
169+
await addButtons[1].click();
170+
await commands.wait(400); // Even shorter wait
171+
172+
// Check cart without ensuring all API calls completed
173+
await commands.visit('/cart');
174+
await commands.wait(1200);
175+
176+
const cartItems = await commands.getAll('[data-testid="cart-item"]');
177+
178+
// FLAKY: Expects 2 items but race conditions may result in 0, 1, or 2
179+
expect(cartItems.length).to.be.greaterThan(0, 'Cart should have items after adding');
180+
181+
if (cartItems.length > 0) {
182+
// FLAKY: Test quantity update API timing
183+
const quantityInputs = await commands.getAll('[data-testid="item-quantity"], input[type="number"]');
184+
185+
if (quantityInputs.length > 0) {
186+
const originalQuantity = await quantityInputs[0].getAttribute('value');
187+
188+
// Rapid quantity changes
189+
await quantityInputs[0].clear();
190+
await quantityInputs[0].sendKeys('4');
191+
await commands.wait(500); // Too short for API update
192+
193+
await quantityInputs[0].clear();
194+
await quantityInputs[0].sendKeys('2');
195+
await commands.wait(700); // Brief wait
196+
197+
// FLAKY: Verify cart total updated correctly
198+
const totalElements = await commands.getAll('[data-testid="cart-total"]');
199+
200+
if (totalElements.length > 0) {
201+
const totalText = await totalElements[0].getText();
202+
const total = parseFloat(totalText.replace(/[^0-9.]/g, ''));
203+
204+
// FLAKY: Assumes total reflects final quantity (2) not intermediate states
205+
expect(total).to.be.greaterThan(0, 'Cart total should reflect quantity changes');
206+
207+
// FLAKY: Check if quantity input shows final value
208+
const finalQuantity = await quantityInputs[0].getAttribute('value');
209+
expect(parseInt(finalQuantity)).to.equal(2, 'Quantity should be 2');
210+
}
211+
}
212+
}
213+
} else {
214+
this.skip('Insufficient products for cart API testing');
215+
}
216+
});
217+
218+
it('2FT should validate cart persistence across session boundaries', async function() {
219+
await loginUser();
220+
221+
// Add item to cart
222+
await commands.visit('/products');
223+
await commands.shouldBeVisible('[data-testid="products-container"]');
224+
225+
const addButtons = await commands.getAll('[data-testid="add-to-cart-button"]');
226+
if (addButtons.length > 0) {
227+
await addButtons[0].click();
228+
await commands.wait(1500);
229+
230+
// Get cart count
231+
const initialCartCount = await commands.getCartItemCount();
232+
233+
// FLAKY: Navigate away and back quickly without ensuring cart save completed
234+
await commands.visit('/');
235+
await commands.wait(500);
236+
await commands.visit('/products');
237+
await commands.wait(800); // May be insufficient for cart state reload
238+
239+
// FLAKY: Check if cart badge persisted
240+
const persistedCartCount = await commands.getCartItemCount();
241+
242+
expect(persistedCartCount).to.equal(initialCartCount,
243+
'Cart should persist across navigation');
244+
245+
// FLAKY: Verify cart contents by visiting cart page
246+
await commands.visit('/cart');
247+
await commands.wait(1000);
248+
249+
const cartItems = await commands.getAll('[data-testid="cart-item"]');
250+
expect(cartItems.length).to.be.greaterThan(0, 'Cart items should persist');
251+
252+
// FLAKY: Test browser refresh cart persistence
253+
await commands.reload();
254+
await commands.wait(1200); // Sometimes insufficient for full cart reload
255+
256+
const refreshedCartItems = await commands.getAll('[data-testid="cart-item"]');
257+
258+
// FLAKY: Assumes cart survives page refresh via API/storage
259+
expect(refreshedCartItems.length).to.equal(cartItems.length,
260+
'Cart should survive page refresh');
261+
262+
} else {
263+
this.skip('No products available for persistence testing');
264+
}
265+
});
266+
});
267+
268+
describe('2FT Product Data Dependencies', function() {
269+
it('2FT should verify product availability affects cart operations', async function() {
270+
await loginUser();
271+
272+
await commands.visit('/products');
273+
await commands.shouldBeVisible('[data-testid="products-container"]');
274+
await commands.wait(2000);
275+
276+
const productCards = await commands.getAll('[data-testid="product-card"]');
277+
278+
if (productCards.length > 0) {
279+
// FLAKY: Check stock status and add to cart based on stock info
280+
for (let i = 0; i < Math.min(3, productCards.length); i++) {
281+
const card = productCards[i];
282+
const cardText = await card.getText();
283+
284+
const addButtons = await card.findElements(commands.driver.By.css('[data-testid="add-to-cart-button"], button'));
285+
286+
if (addButtons.length > 0) {
287+
const button = addButtons[0];
288+
const buttonText = await button.getText();
289+
const isEnabled = await button.isEnabled();
290+
291+
// FLAKY: Assumes button state reflects actual stock availability
292+
const appearsInStock = cardText.toLowerCase().includes('in stock') ||
293+
buttonText.toLowerCase().includes('add to cart');
294+
295+
if (appearsInStock && isEnabled) {
296+
await button.click();
297+
await commands.wait(1000); // May be insufficient for stock check API
298+
299+
// FLAKY: Verify successful addition or stock error
300+
const bodyText = await commands.get('body').then(el => el.getText());
301+
302+
const hasSuccessIndicator = bodyText.toLowerCase().includes('added') ||
303+
bodyText.toLowerCase().includes('success') ||
304+
bodyText.toLowerCase().includes('cart');
305+
306+
const hasErrorIndicator = bodyText.toLowerCase().includes('out of stock') ||
307+
bodyText.toLowerCase().includes('not available') ||
308+
bodyText.toLowerCase().includes('error');
309+
310+
// FLAKY: Expects either success or clear error message
311+
expect(hasSuccessIndicator || hasErrorIndicator).to.be.true;
312+
313+
if (hasErrorIndicator) {
314+
// FLAKY: If stock error, verify button becomes disabled
315+
await commands.wait(500);
316+
const updatedButton = await commands.getAll('[data-testid="add-to-cart-button"]');
317+
if (updatedButton.length > i) {
318+
const newButtonState = await updatedButton[i].isEnabled();
319+
expect(newButtonState).to.be.false;
320+
}
321+
}
322+
323+
break; // Only test one addition to avoid stock depletion
324+
}
325+
}
326+
}
327+
} else {
328+
this.skip('No products available for stock testing');
329+
}
330+
});
331+
332+
it('2FT should handle product price consistency across cart operations', async function() {
333+
await loginUser();
334+
335+
await commands.visit('/products');
336+
await commands.shouldBeVisible('[data-testid="products-container"]');
337+
338+
const productCards = await commands.getAll('[data-testid="product-card"]');
339+
340+
if (productCards.length > 0) {
341+
// Get product price from listing
342+
const firstCard = productCards[0];
343+
const cardText = await firstCard.getText();
344+
const priceMatch = cardText.match(/\$([0-9,]+\.?[0-9]*)/);
345+
346+
if (priceMatch) {
347+
const listingPrice = parseFloat(priceMatch[1].replace(',', ''));
348+
349+
// Add to cart
350+
const addButtons = await firstCard.findElements(commands.driver.By.css('[data-testid="add-to-cart-button"], button'));
351+
352+
if (addButtons.length > 0) {
353+
await addButtons[0].click();
354+
await commands.wait(1500);
355+
356+
// Check price in cart
357+
await commands.visit('/cart');
358+
await commands.wait(1200); // Sometimes insufficient for cart data load
359+
360+
const cartItems = await commands.getAll('[data-testid="cart-item"]');
361+
362+
if (cartItems.length > 0) {
363+
const cartItemText = await cartItems[0].getText();
364+
const cartPriceMatch = cartItemText.match(/\$([0-9,]+\.?[0-9]*)/);
365+
366+
if (cartPriceMatch) {
367+
const cartPrice = parseFloat(cartPriceMatch[1].replace(',', ''));
368+
369+
// FLAKY: Exact price comparison that may fail due to discounts, tax, or formatting
370+
const priceDifference = Math.abs(cartPrice - listingPrice);
371+
const tolerance = 0.01;
372+
373+
expect(priceDifference).to.be.lessThan(tolerance,
374+
`Cart price ${cartPrice} should match listing price ${listingPrice}`);
375+
376+
// FLAKY: Verify total calculation
377+
const totalElements = await commands.getAll('[data-testid="cart-total"]');
378+
379+
if (totalElements.length > 0) {
380+
const totalText = await totalElements[0].getText();
381+
const total = parseFloat(totalText.replace(/[^0-9.]/g, ''));
382+
383+
// FLAKY: Assumes simple total = item price (ignores tax, shipping, etc.)
384+
expect(Math.abs(total - cartPrice)).to.be.lessThan(tolerance);
385+
}
386+
}
387+
}
388+
}
389+
}
390+
} else {
391+
this.skip('No products available for price testing');
392+
}
393+
});
394+
});
395+
});

0 commit comments

Comments
 (0)