Skip to content

Commit

Permalink
#80 Add pages for products and cart
Browse files Browse the repository at this point in the history
  • Loading branch information
Yashmerino committed Mar 6, 2024
1 parent 23b18af commit 2099342
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.yashmerino.online.shop.selenium.it.pages;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.WebDriverWait;

/**
* Base class for pages that have the header component.
*/
public class BaseHeaderPage extends BasePage {
/**
* My Profile header button.
*/
private final By profileButton = By.id("profile-button");

/**
* My Cart header button.
*/
private final By myCartButton = By.id("my-cart-button");

/**
* My Products header button.
*/
private final By myProductsButton = By.id("my-products-button");

/**
* Add Product header button.
*/
private final By addProductsButton = By.id("add-products-button");

/**
* Constructor.
*
* @param driver web driver to perform browser actions.
* @param wait wait web driver to wait until certain conditions met.
*/
public BaseHeaderPage(WebDriver driver, WebDriverWait wait) {
super(driver, wait);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,22 @@ public class BasePage {
/**
* Web Driver to make browser actions.
*/
protected WebDriver driver;
protected final WebDriver driver;

/**
* Wait web driver to wait until certain conditions met.
*/
protected WebDriverWait wait;
protected final WebDriverWait wait;

/**
* Success alert element.
*/
protected By successAlert = By.id("alert-success");
protected final By successAlert = By.id("alert-success");

/**
* Submit button.
*/
protected final By submitButton = By.id("submit-button");

/**
* Constructor.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.yashmerino.online.shop.selenium.it.pages.cart;

import com.yashmerino.online.shop.selenium.it.pages.BaseHeaderPage;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.WebDriverWait;

/**
* Page Object Model that represents my cart page.
*/
public class MyCartPage extends BaseHeaderPage {
/**
* Constructor.
*
* @param driver web driver to perform browser actions.
* @param wait wait web driver to wait until certain conditions met.
*/
public MyCartPage(final WebDriver driver, final WebDriverWait wait) {
super(driver, wait);
}

/**
* Checks if a product exists.
*
* @param productName is the product's name.
* @return <code>true</code> or <code>false</code>.
*/
public boolean productExists(final String productName) {
try {
driver.findElement(By.xpath(String.format("//h6[contains(string(), %s)]", productName)));
return true;
} catch (NoSuchElementException e) {
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.yashmerino.online.shop.selenium.it.pages.products;

import com.yashmerino.online.shop.selenium.it.pages.BaseHeaderPage;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

/**
* Page Object Model that represents add product page.
*/
public class AddProductPage extends BaseHeaderPage {
/**
* Name field.
*/
private final By nameField = By.id("name-field");

/**
* Constructor.
*
* @param driver web driver to perform browser actions.
* @param wait wait web driver to wait until certain conditions met.
*/
public AddProductPage(final WebDriver driver, final WebDriverWait wait) {
super(driver, wait);
}

/**
* Adds a product.
*
* @param productName is the product's name.
*/
public void addProductToCard(final String productName) {
driver.findElement(nameField).sendKeys(productName);
driver.findElement(submitButton).click();

wait.until(ExpectedConditions.visibilityOfElementLocated(successAlert));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.yashmerino.online.shop.selenium.it.pages.products;

import com.yashmerino.online.shop.selenium.it.pages.BaseHeaderPage;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.WebDriverWait;

/**
* Page Object Model that represents my products page.
*/
public class MyProductsPage extends BaseHeaderPage {
/**
* Constructor.
*
* @param driver web driver to perform browser actions.
* @param wait wait web driver to wait until certain conditions met.
*/
public MyProductsPage(final WebDriver driver, final WebDriverWait wait) {
super(driver, wait);
}

/**
* Checks if a product exists.
*
* @param productName is the product's name.
* @return <code>true</code> or <code>false</code>.
*/
public boolean productExists(final String productName) {
try {
driver.findElement(By.xpath(String.format("//h6[contains(string(), %s)]", productName)));
return true;
} catch (NoSuchElementException e) {
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.yashmerino.online.shop.selenium.it.pages.products;

import com.yashmerino.online.shop.selenium.it.pages.BaseHeaderPage;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

/**
* Page Object Model that represents products page.
*/
public class ProductsPage extends BaseHeaderPage {

/**
* Constructor.
*
* @param driver web driver to perform browser actions.
* @param wait wait web driver to wait until certain conditions met.
*/
public ProductsPage(final WebDriver driver, final WebDriverWait wait) {
super(driver, wait);
}

/**
* Adds a product to the card.
*
* @param productId is the product's id.
*/
public void addProductToCard(final String productId) {
driver.findElement(By.id("add-product-" + productId)).click();

wait.until(ExpectedConditions.visibilityOfElementLocated(successAlert));
}
}
8 changes: 4 additions & 4 deletions online-shop-ui/src/app/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,20 +199,20 @@ const Header = () => {
{getTranslation(lang, "online_shop")}
</Typography>
<Box sx={{ flexGrow: 1, display: { xs: 'none', md: 'flex' } }}>
<Button key={1} startIcon={<AccountCircleIcon />} onClick={handleProfile} sx={{ ml: "2vh", my: 2, color: 'white', display: 'flex', fontWeight: "Bold" }}>{getTranslation(lang, "profile")}</Button>
<Button key={1} startIcon={<AccountCircleIcon />} onClick={handleProfile} id="profile-button" sx={{ ml: "2vh", my: 2, color: 'white', display: 'flex', fontWeight: "Bold" }}>{getTranslation(lang, "profile")}</Button>
{// @ts-ignore
roles[0].name == "USER" ?
<Button key={2} startIcon={<ShoppingCartIcon />} onClick={handleMyCart} sx={{ ml: "2vh", my: 2, color: 'white', display: 'flex', fontWeight: "Bold" }}>{getTranslation(lang, "my_cart")}</Button> :
<Button key={2} startIcon={<ShoppingCartIcon />} onClick={handleMyCart} id="my-cart-button" sx={{ ml: "2vh", my: 2, color: 'white', display: 'flex', fontWeight: "Bold" }}>{getTranslation(lang, "my_cart")}</Button> :
null
}
{// @ts-ignore
roles[0].name == "SELLER" ?
<Button key={3} startIcon={<AddIcon />} onClick={handleAddProduct} sx={{ ml: "2vh", my: 2, color: 'white', display: 'flex', fontWeight: "Bold" }}>{getTranslation(lang, "add_product")}</Button> :
<Button key={3} startIcon={<AddIcon />} onClick={handleAddProduct} id="add-product-button" sx={{ ml: "2vh", my: 2, color: 'white', display: 'flex', fontWeight: "Bold" }}>{getTranslation(lang, "add_product")}</Button> :
null
}
{// @ts-ignore
roles[0].name == "SELLER" ?
<Button key={4} startIcon={<SellIcon />} onClick={handleMyProducts} sx={{ ml: "2vh", my: 2, color: 'white', display: 'flex', fontWeight: "Bold" }}>{getTranslation(lang, "my_products")}</Button> :
<Button key={4} startIcon={<SellIcon />} onClick={handleMyProducts} id="my-products-button" sx={{ ml: "2vh", my: 2, color: 'white', display: 'flex', fontWeight: "Bold" }}>{getTranslation(lang, "my_products")}</Button> :
null
}
{// @ts-ignore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ const AddProductPage = () => {
</Box>
</Paper>
<Button
id="submit-button"
type="submit"
data-testid="submit-button"
variant="contained"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { useAppSelector } from '../../../hooks'
import { Stack, Typography } from '@mui/material';
import { getCategories } from '../../../api/CategoryRequest';
import { getTranslation } from '../../../../i18n/i18n';
import NoPhoto from "../../../../img/no_photo.jpg";

const MenuProps = {
PaperProps: {
Expand Down Expand Up @@ -77,7 +78,7 @@ const EditProductPage = () => {
const [error, setError] = React.useState("");
const [isSuccess, setSuccess] = React.useState(false);

const [photo, setPhoto] = React.useState("");
const [photo, setPhoto] = React.useState(NoPhoto);
const [file, setFile] = React.useState<File | null>(null);

const handleAlertClick = () => {
Expand All @@ -104,8 +105,11 @@ const EditProductPage = () => {

const getProductPhotoRequest = async () => {
const photoBlob = await getProductPhoto(location.state ? location.state.id : "1");
setPhoto(URL.createObjectURL(photoBlob));
setFile(photoBlob as File);
if(photoBlob.size > 0) {
setPhoto(URL.createObjectURL(photoBlob));
setFile(photoBlob as File);
}

}

getProductPhotoRequest();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ const ProductCard = ({ id, title, price, categories, description }: ProductCardP
<img width={"100%"} height={"100%"} src={photo} data-testid={"card-image-" + id} style={{ objectFit: "cover", borderRadius: "15px" }} />
{// @ts-ignore
roles[0].name == "USER" ? (
<IconButton color="primary" aria-label="add to shopping cart" onClick={handleAddProduct} sx={{ marginLeft: "83%", border: "1px solid", width: "15%", height: "25%" }}>
<IconButton color="primary" aria-label="add to shopping cart" onClick={handleAddProduct} id={"add-product-" + id} sx={{ marginLeft: "83%", border: "1px solid", width: "15%", height: "25%" }}>
{/* NOSONAR: Function addProduct doesn't return Promise.*/}
<AddShoppingCartIcon />
</IconButton>) : null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const ProductsContainer = () => {
<Paper square elevation={3} sx={{ width: "70%", pb: "1.5%", margin: "auto", mt: "2.5%", display: "flex", overflow: "hidden" }}>
<Grid container justifyContent="center" alignItems="center" columnGap={4}>
{products.length > 0 && products.map(product => {
return (<div style={{ marginTop: "2.5%" }}><ProductCard key={product.objectID} id={product.objectID} title={product.name} price={product.price} categories={product.categories} description={product.description} /></div>);
return (<div style={{ marginTop: "2.5%" }} key={product.objectID}><ProductCard key={product.objectID} id={product.objectID} title={product.name} price={product.price} categories={product.categories} description={product.description} /></div>);
})}
{products.length <= 0 &&
<Typography variant="h4" sx={{ margin: "auto", mt: "5%", mb: "3.5%" }}>{getTranslation(lang, "no_products_found")}</Typography>
Expand Down

0 comments on commit 2099342

Please sign in to comment.