Skip to content

Commit 5068068

Browse files
committed
Added layer: steps.
1 parent b649a64 commit 5068068

File tree

12 files changed

+574
-228
lines changed

12 files changed

+574
-228
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package qa.autotest.framework.steps;
2+
3+
import io.qameta.allure.Step;
4+
import lombok.RequiredArgsConstructor;
5+
import lombok.extern.slf4j.Slf4j;
6+
import qa.autotest.domain.dto.UserDto;
7+
import qa.autotest.framework.config.TestConfig;
8+
import qa.autotest.framework.pages.InventoryPage;
9+
import qa.autotest.framework.pages.LoginPage;
10+
11+
/**
12+
* Business-level authentication steps.
13+
*
14+
* <p>Encapsulates the login/logout flow so test classes express <em>intent</em>
15+
* ("login as standard user") rather than <em>mechanics</em> (open page →
16+
* fill credentials → click → wait).
17+
*
18+
* <p>All duplicated {@code @BeforeEach loginAndNavigate()} blocks across
19+
* {@code CartOperationsTests}, {@code CheckoutFlowTests},
20+
* {@code InventoryDisplayTests}, {@code InventorySortingTests}, and
21+
* {@code NavigationTests} delegate to methods in this class.
22+
*
23+
* <p>Stateless: every method receives a {@link LoginPage} entry point and
24+
* returns the resulting page object. No mutable fields — safe under parallel
25+
* execution where each thread owns its own {@link LoginPage} instance.
26+
*/
27+
@Slf4j
28+
@RequiredArgsConstructor
29+
public class AuthSteps {
30+
31+
private final TestConfig config;
32+
33+
/**
34+
* Opens the login page and authenticates with standard-user credentials.
35+
*
36+
* @param loginPage entry-point page object (created by {@code BaseTest.setUp()})
37+
* @return {@link InventoryPage} after successful authentication
38+
*/
39+
@Step("Login as standard user")
40+
public InventoryPage loginAsStandardUser(LoginPage loginPage) {
41+
log.info("Logging in as standard user");
42+
return loginPage
43+
.openPage(config.sauceDemoBaseUrl())
44+
.login(config.standardUsername(), config.standardPassword())
45+
.waitForPageLoad();
46+
}
47+
48+
/**
49+
* Opens the login page and authenticates with locked-user credentials.
50+
* Expects an error — does not navigate away from the login page.
51+
*
52+
* @param loginPage entry-point page object
53+
* @return {@link LoginPage} with visible error message
54+
*/
55+
@Step("Attempt login as locked user (expecting error)")
56+
public LoginPage loginAsLockedUser(LoginPage loginPage) {
57+
log.info("Attempting login as locked user");
58+
return loginPage
59+
.openPage(config.sauceDemoBaseUrl())
60+
.loginWithError(config.lockedUsername(), config.lockedPassword());
61+
}
62+
63+
/**
64+
* Opens the login page and authenticates with the supplied {@link UserDto}.
65+
* Use for parameterised / data-driven tests.
66+
*
67+
* @param loginPage entry-point page object
68+
* @param user credentials DTO
69+
* @return {@link InventoryPage} after successful authentication
70+
*/
71+
@Step("Login as user: {user.username}")
72+
public InventoryPage loginAs(LoginPage loginPage, UserDto user) {
73+
log.info("Logging in as user: {}", user.getUsername());
74+
return loginPage
75+
.openPage(config.sauceDemoBaseUrl())
76+
.login(user)
77+
.waitForPageLoad();
78+
}
79+
80+
/**
81+
* Opens the login page and submits the supplied credentials, expecting an
82+
* error response.
83+
*
84+
* @param loginPage entry-point page object
85+
* @param username credentials to submit
86+
* @param password credentials to submit
87+
* @return {@link LoginPage} with visible error message
88+
*/
89+
@Step("Attempt login with username: {username} (expecting error)")
90+
public LoginPage loginWithError(LoginPage loginPage, String username, String password) {
91+
log.info("Attempting login with username: {} (expecting error)", username);
92+
return loginPage
93+
.openPage(config.sauceDemoBaseUrl())
94+
.loginWithError(username, password);
95+
}
96+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package qa.autotest.framework.steps;
2+
3+
import io.qameta.allure.Step;
4+
import lombok.extern.slf4j.Slf4j;
5+
import qa.autotest.domain.enums.SauceDemoProduct;
6+
import qa.autotest.framework.pages.CartPage;
7+
import qa.autotest.framework.pages.InventoryPage;
8+
9+
/**
10+
* Business-level cart steps.
11+
*
12+
* <p>Encapsulates compound cart operations: adding one or more products,
13+
* clearing the cart, and navigating to the cart page. Tests express
14+
* <em>what</em> they need ("cart with two products") rather than
15+
* <em>how</em> to assemble it.
16+
*
17+
* <p>Stateless: every method receives the required page-object context and
18+
* returns the resulting page object. Safe under parallel execution.
19+
*/
20+
@Slf4j
21+
public class CartSteps {
22+
23+
/**
24+
* Adds a single product to the cart by its canonical enum constant.
25+
*
26+
* @param inventoryPage active inventory page
27+
* @param product product to add
28+
* @return the same {@link InventoryPage} for further chaining
29+
*/
30+
@Step("Add product to cart: {product}")
31+
public InventoryPage addProduct(InventoryPage inventoryPage, SauceDemoProduct product) {
32+
log.info("Adding product to cart: {}", product.getDisplayName());
33+
return inventoryPage.addProductToCartByName(product);
34+
}
35+
36+
/**
37+
* Adds every supplied product to the cart in the given order.
38+
*
39+
* @param inventoryPage active inventory page
40+
* @param products one or more products to add
41+
* @return the same {@link InventoryPage} for further chaining
42+
*/
43+
@Step("Add products to cart: {products}")
44+
public InventoryPage addProducts(InventoryPage inventoryPage, SauceDemoProduct... products) {
45+
log.info("Adding {} product(s) to cart", products.length);
46+
for (SauceDemoProduct product : products) {
47+
inventoryPage.addProductToCartByName(product);
48+
}
49+
return inventoryPage;
50+
}
51+
52+
/**
53+
* Adds a product by its 0-based display index on the inventory page.
54+
* Prefer {@link #addProduct(InventoryPage, SauceDemoProduct)} when the
55+
* product identity matters for the assertion; use this only when the
56+
* specific product is irrelevant.
57+
*
58+
* @param inventoryPage active inventory page
59+
* @param index 0-based product index
60+
* @return the same {@link InventoryPage} for further chaining
61+
*/
62+
@Step("Add product at index {index} to cart")
63+
public InventoryPage addProductByIndex(InventoryPage inventoryPage, int index) {
64+
log.info("Adding product at index {} to cart", index);
65+
return inventoryPage.addProductToCartByIndex(index);
66+
}
67+
68+
/**
69+
* Navigates to the cart page and waits for it to load.
70+
*
71+
* @param inventoryPage active inventory page
72+
* @return loaded {@link CartPage}
73+
*/
74+
@Step("Open cart")
75+
public CartPage openCart(InventoryPage inventoryPage) {
76+
log.info("Opening cart");
77+
return inventoryPage.openCart().waitForPageLoad();
78+
}
79+
80+
/**
81+
* Adds the given products and immediately opens the cart page.
82+
* Covers the common test setup: "given a cart with N items, when I open
83+
* the cart, then…".
84+
*
85+
* @param inventoryPage active inventory page
86+
* @param products products to add before navigating
87+
* @return loaded {@link CartPage}
88+
*/
89+
@Step("Add products and open cart: {products}")
90+
public CartPage addProductsAndOpenCart(InventoryPage inventoryPage,
91+
SauceDemoProduct... products) {
92+
log.info("Adding {} product(s) and opening cart", products.length);
93+
addProducts(inventoryPage, products);
94+
return openCart(inventoryPage);
95+
}
96+
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package qa.autotest.framework.steps;
2+
3+
import io.qameta.allure.Step;
4+
import lombok.RequiredArgsConstructor;
5+
import lombok.extern.slf4j.Slf4j;
6+
import qa.autotest.domain.dto.CheckoutDto;
7+
import qa.autotest.domain.enums.SauceDemoProduct;
8+
import qa.autotest.framework.config.TestConfig;
9+
import qa.autotest.framework.pages.CartPage;
10+
import qa.autotest.framework.pages.CheckoutCompletePage;
11+
import qa.autotest.framework.pages.CheckoutStepOnePage;
12+
import qa.autotest.framework.pages.CheckoutStepTwoPage;
13+
import qa.autotest.framework.pages.InventoryPage;
14+
15+
/**
16+
* Business-level checkout steps.
17+
*
18+
* <p>Covers the full checkout funnel — from cart to confirmation — in a single
19+
* method call. Tests describe the <em>scenario under test</em> rather than
20+
* every page-navigation detail.
21+
*
22+
* <p>Config-sourced checkout data ({@code checkoutFirstName}, etc.) is read
23+
* once via the injected {@link TestConfig}. Tests that need custom data
24+
* pass an explicit {@link CheckoutDto}.
25+
*
26+
* <p>Stateless: safe under parallel execution.
27+
*/
28+
@Slf4j
29+
@RequiredArgsConstructor
30+
public class CheckoutSteps {
31+
32+
private final TestConfig config;
33+
34+
/**
35+
* Navigates from the cart page to {@link CheckoutStepOnePage}.
36+
*
37+
* @param cartPage loaded cart page
38+
* @return loaded {@link CheckoutStepOnePage}
39+
*/
40+
@Step("Proceed to checkout info page")
41+
public CheckoutStepOnePage proceedToCheckoutInfo(CartPage cartPage) {
42+
log.info("Proceeding from cart to checkout step one");
43+
return cartPage.proceedToCheckout().waitForPageLoad();
44+
}
45+
46+
/**
47+
* Fills checkout info from config and proceeds to the overview page.
48+
*
49+
* @param checkoutInfoPage loaded checkout step-one page
50+
* @return loaded {@link CheckoutStepTwoPage}
51+
*/
52+
@Step("Fill checkout info from config and continue")
53+
public CheckoutStepTwoPage fillInfoAndContinue(CheckoutStepOnePage checkoutInfoPage) {
54+
log.info("Filling checkout info from config");
55+
return checkoutInfoPage
56+
.fillCheckoutInfo(
57+
config.checkoutFirstName(),
58+
config.checkoutLastName(),
59+
config.checkoutZipCode())
60+
.clickContinue()
61+
.waitForPageLoad();
62+
}
63+
64+
/**
65+
* Fills checkout info from the supplied DTO and proceeds to the overview page.
66+
*
67+
* @param checkoutInfoPage loaded checkout step-one page
68+
* @param checkoutDto checkout data
69+
* @return loaded {@link CheckoutStepTwoPage}
70+
*/
71+
@Step("Fill checkout info from DTO and continue")
72+
public CheckoutStepTwoPage fillInfoAndContinue(CheckoutStepOnePage checkoutInfoPage,
73+
CheckoutDto checkoutDto) {
74+
log.info("Filling checkout info: {} {} {}",
75+
checkoutDto.getFirstName(), checkoutDto.getLastName(), checkoutDto.getZipCode());
76+
return checkoutInfoPage
77+
.fillCheckoutInfo(checkoutDto)
78+
.clickContinue()
79+
.waitForPageLoad();
80+
}
81+
82+
/**
83+
* Runs the complete checkout funnel:
84+
* add product → open cart → fill info (from config) → overview → finish.
85+
*
86+
* <p>Use when the test under verification is <em>after</em> checkout
87+
* completes (e.g. order confirmation, empty cart).
88+
*
89+
* @param inventoryPage active inventory page
90+
* @param product product to purchase
91+
* @return loaded {@link CheckoutCompletePage}
92+
*/
93+
@Step("Complete checkout with product: {product}")
94+
public CheckoutCompletePage completeCheckout(InventoryPage inventoryPage,
95+
SauceDemoProduct product) {
96+
log.info("Running full checkout for product: {}", product.getDisplayName());
97+
return inventoryPage
98+
.addProductToCartByName(product)
99+
.openCart()
100+
.proceedToCheckout()
101+
.fillCheckoutInfo(
102+
config.checkoutFirstName(),
103+
config.checkoutLastName(),
104+
config.checkoutZipCode())
105+
.clickContinue()
106+
.waitForPageLoad()
107+
.clickFinish()
108+
.waitForPageLoad();
109+
}
110+
111+
/**
112+
* Runs the complete checkout funnel with a custom {@link CheckoutDto}.
113+
*
114+
* @param inventoryPage active inventory page
115+
* @param product product to purchase
116+
* @param checkoutDto checkout data
117+
* @return loaded {@link CheckoutCompletePage}
118+
*/
119+
@Step("Complete checkout with product: {product}, info: {checkoutDto}")
120+
public CheckoutCompletePage completeCheckout(InventoryPage inventoryPage,
121+
SauceDemoProduct product,
122+
CheckoutDto checkoutDto) {
123+
log.info("Running full checkout for product: {} with custom info", product.getDisplayName());
124+
return inventoryPage
125+
.addProductToCartByName(product)
126+
.openCart()
127+
.proceedToCheckout()
128+
.fillCheckoutInfo(checkoutDto)
129+
.clickContinue()
130+
.waitForPageLoad()
131+
.clickFinish()
132+
.waitForPageLoad();
133+
}
134+
135+
/**
136+
* Navigates from inventory through cart to the overview page without
137+
* finishing the order. Use when the test verifies the overview page itself
138+
* (totals, item list).
139+
*
140+
* @param inventoryPage active inventory page
141+
* @param products one or more products to add
142+
* @return loaded {@link CheckoutStepTwoPage}
143+
*/
144+
@Step("Reach checkout overview with products: {products}")
145+
public CheckoutStepTwoPage reachCheckoutOverview(InventoryPage inventoryPage,
146+
SauceDemoProduct... products) {
147+
log.info("Reaching checkout overview with {} product(s)", products.length);
148+
for (SauceDemoProduct product : products) {
149+
inventoryPage.addProductToCartByName(product);
150+
}
151+
return inventoryPage
152+
.openCart()
153+
.proceedToCheckout()
154+
.fillCheckoutInfo(
155+
config.checkoutFirstName(),
156+
config.checkoutLastName(),
157+
config.checkoutZipCode())
158+
.clickContinue()
159+
.waitForPageLoad();
160+
}
161+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package qa.autotest.framework.steps;
2+
3+
import io.qameta.allure.Step;
4+
import lombok.extern.slf4j.Slf4j;
5+
import qa.autotest.framework.pages.InventoryPage;
6+
import qa.autotest.framework.pages.ProductDetailsPage;
7+
8+
/**
9+
* Business-level inventory steps.
10+
*
11+
* <p>Covers navigation and interaction patterns on the inventory/catalog page
12+
* that appear repeatedly across test classes.
13+
*
14+
* <p>Stateless: safe under parallel execution.
15+
*/
16+
@Slf4j
17+
public class InventorySteps {
18+
19+
/**
20+
* Opens the product details page for the named product.
21+
*
22+
* @param inventoryPage active inventory page
23+
* @param productName display name of the product to open
24+
* @return loaded {@link ProductDetailsPage}
25+
*/
26+
@Step("Open product details: {productName}")
27+
public ProductDetailsPage openProductDetails(InventoryPage inventoryPage, String productName) {
28+
log.info("Opening product details for: {}", productName);
29+
return inventoryPage.openProductDetails(productName).waitForPageLoad();
30+
}
31+
}

0 commit comments

Comments
 (0)