Currently How to test a callback function with JEST + React? - reactjs

I would like to test this component:
the parameter received in onClick={() => onConfirmVote(number)}
The value returned in getVoteText
MY CODE:
function CandidateList({ data }: IProps) {
const { convertToCurrency, convertToPercentage } = useNumberConversion();
const getVoteText = useCallback(
(total: number, percentage: number) => `${convertToCurrency(total)} (${convertToPercentage(percentage)})`,
[convertToCurrency, convertToPercentage]
);
return (
<ListGroup data-testid='candidate-list-component'>
{data.map(({ onConfirmVote, avatar, number, votesConfirmed, hasVoted }) => (
<ListGroup.Item key={`${number}`} as='li' className='d-flex flex-wrap gap-2 align-items-center'>
<div className='d-flex justify-content-between align-items-center w-100'>
<div className='d-flex flex-wrap align-items-center gap-2'>
<Avatar alt={`Candidate #${number}`} src={avatar} />
<h5 className='fw-bold mb-0'>#{number}</h5>
</div>
<div className='mt-1 d-flex flex-wrap align-items-center gap-2'>
<span className='mb-1'>Votes:</span>
<Badge bg='primary' pill style={{ width: '155px' }} data-testid='badge-vote-value-component'>
{getVoteText(votesConfirmed.total, votesConfirmed.totalPercentage)}
</Badge>
</div>
</div>
<Button className='w-100' variant='success' onClick={() => onConfirmVote(number)} disabled={hasVoted}>
CONFIRM
</Button>
</ListGroup.Item>
))}
</ListGroup>
);
}
MY TESTE CODE:
describe('[CANDIDATE LIST] - Testing Confirm Vote Button Component', () => {
test('Should be work on click to Confirm Vote!', () => {
render(<CandidateList data={MOCKED_DATA} />);
const confirmVoteButton = screen.getAllByRole('button');
confirmVoteButton.forEach(button => {
console.log(button);
expect(fireEvent.click(button)).toBe(true);
});
});
});

I have simplified your component and you can try sth like this:
the component
import React from "react";
const ManyButtons = ({ data }) => {
const getVoteText = (total, percentage) => `${total} (${percentage})`;
return (
<div>
{data.map(({ onConfirmVote, number, votesConfirmed: { total, totalPercentage } }, index) => (
<div key={index}>
<div>{getVoteText(total, totalPercentage)}</div>
<button onClick={() => onConfirmVote(number)}>
CONFIRM
</button>
</div>
))}
</div>
);
};
export default ManyButtons;
The test:
import { screen, render, fireEvent } from "#testing-library/react";
import ManyButtons from "../ManyButton";
const mockOnConfirmVote = jest.fn();
const mockedData = [
{ onConfirmVote: mockOnConfirmVote, number: 1, votesConfirmed: { total: 1, totalPercentage: 1 } },
{ onConfirmVote: mockOnConfirmVote, number: 2, votesConfirmed: { total: 2, totalPercentage: 2 } },
{ onConfirmVote: mockOnConfirmVote, number: 3, votesConfirmed: { total: 3, totalPercentage: 3 } },
]
describe('it should work', () => {
it('should work', () => {
render(<ManyButtons data={mockedData} />);
const buttons = screen.getAllByRole('button', { name: /confirm/i });
expect(buttons).toHaveLength(mockedData.length);
buttons.forEach(btn => fireEvent.click(btn))
expect(mockOnConfirmVote).toHaveBeenCalledTimes(buttons.length);
mockedData.forEach(({ number, votesConfirmed: { total, totalPercentage }}) => {
expect(mockOnConfirmVote).toHaveBeenCalledWith(number);
expect(screen.getByText(`${total} (${totalPercentage})`)).toBeInTheDocument();
})
})
})

Related

how to add data in localstorage in react

I am arslan Chaudhry. currently, I am working on an eCommerce site where I will store data in local storage because I don't have too much backend knowledge. how I can add functionality like delete and update on another folder.
my code is given below.
Books.js
import React from "react";
import "./components/book.css";
import Carousel from "react-multi-carousel";
import "react-multi-carousel/lib/styles.css";
import { FaShoppingCart } from "react-icons/fa";
import { useEffect } from "react";
import { useState, useRef } from "react";
import { useNavigate } from "react-router-dom";
import { createContext } from "react";
const Books = () => {
let arr=()=>{
let dat=localStorage.getItem("products")
if (dat) {
return JSON.parse(dat)
}
else{
return []
}
}
const [booksData, setbooksData] = useState([]);
const [productData, setproductData] = useState(arr());
let nav = useNavigate();
// slider
const responsive = {
superLargeDesktop: {
breakpoint: { max: 4000, min: 3000 },
items: 5,
},
desktop: {
breakpoint: { max: 3000, min: 1024 },
items: 3,
},
tablet: {
breakpoint: { max: 1024, min: 464 },
items: 2,
},
mobile: {
breakpoint: { max: 464, min: 0 },
items: 1,
},
};
let croser = useRef("");
let loding = useRef("");
const getJason = async () => {
try {
let fea = await fetch(
"https://script.google.com/macros/s/AKfycbxFCG7S-kjncQZwvcMnqq4wXoBAX8ecH1zkY2bLP7EE-YHlnKbiJ3RUuHtWLe6sIK30Kw/exec"
);
let acData = await fea.json();
let itemsData = acData.shop.filter((element) => {
if (element.name) {
return element;
}
});
setbooksData(itemsData);
if (itemsData) {
croser.current.style.filter = "blur(0px)";
loding.current.style.display = "none";
}
} catch (error) {
croser.current.style.filter = "blur(0px)";
loding.current.style.display = "none";
}
};
// get product data from api
useEffect(() => {
getJason();
}, []);
// go to cart button
const goto = () => {
nav("/Cart");
};
// local data
let addNow=(e)=>{
let data=productData.find((element)=>{return element.id === e.id });
let cart;
if (data) {
cart=productData.map((element)=>{
return element.id === e.id ? {...element, quantity:element.quantity+1}:element
})
}
else{
cart=[...productData,{...e, quantity:1}]
}
setproductData(cart);
};
useEffect(() => {
localStorage.setItem("products",JSON.stringify(productData))
}, [productData])
console.log(productData);
return (
<>
<div className="row " style={{ marginTop: "10px" }}>
<div className="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div className="section-headline text-center">
<h2>Books Shop</h2>
</div>
</div>
</div>
<div className="lodingBooks" ref={loding}>
<div class="spinner-border" role="status"></div>
<h4>Please wait....</h4>
</div>
<div ref={croser}>
<div className=" shadow go_to_cart" onClick={goto}>
<i class="bi bi-cart-check text-white"></i>
</div>
<Carousel responsive={responsive} className="container">
{booksData.map((element) => {
return (
<>
<div class="container page-wrapper">
<div class="page-inner">
<div class="row">
<div class="el-wrapper">
<div class="box-up">
<img class="img" src={element.images} alt="" />
<div class="img-info">
<div class="info-inner">
<span class="p-name text-info">
{element.name}
</span>
<span class="p-company ">Author:CHAUDHRY</span>
</div>
<div class="a-size ">
About:This is a complete book on javascript
<span class="size"></span>
</div>
</div>
</div>
<input
type="text"
value={1}
style={{ display: "none" }}
/>
<div class="box-down">
<div class="h-bg">
<div class="h-bg-inner"></div>
</div>
<a class="cart">
<span class="price">{element.price + "$"}</span>
<span
class="add-to-cart btn btn-sm"
style={{ backgroundColor: "#3EC1D5" }}
onClick={()=>{addNow(element)}}
>
<span class="txt">
ADD TO CART <FaShoppingCart />
</span>
</span>
</a>
</div>
</div>
</div>
</div>
</div>
</>
);
})}
</Carousel>
</div>
</>
);
};
export default Books;
and here is my cart file. where i want to perform the action like update and delete.
Cart.js
import React from "react";
import "./components/cart.css";
import { useEffect } from "react";
const Cart = () => {
let data = localStorage.getItem("products");
let javaData = JSON.parse(data);
let removeData = (e) => {
};
useEffect(() => {
localStorage.clear()
}, [])
return (
<>
<div class="container mt-5 mb-5">
<div class="d-flex justify-content-center row">
<div class="col-md-8">
<div class="p-2 shoingTitle">
<h4>Shop Now</h4>
<span class="text-danger">Remove all</span>
</div>
{javaData ? (
javaData.map((item) => {
return (
<>
<div class="d-flex flex-row justify-content-between align-items-center p-2 bg-white mt-4 px-3 rounded">
<div class="mr-1 imageandpara">
<img class="rounded" src={item.images} width="70" />
<span class="font-weight-bold">{item.name}</span>
</div>
<div class="d-flex flex-column align-items-center product-details">
<div class="d-flex flex-row product-desc"></div>
</div>
<div class="d-flex flex-row align-items-center qty">
<i class="minusSign shadow">
<i class="bi bi-dash"></i>
</i>
<span class="text-grey quantityNumber">
{item.quantity}
</span>
<i class="minusSign shadow">
<i class="bi bi-plus"></i>
</i>
</div>
<div>
<span class="text-grey productAmount">{`${
item.quantity * item.price
}$`}</span>
</div>
<div
class="d-flex align-items-center text-dark "
style={{
cursor: "pointer",
fontWeight: "900",
fontSize: "15px",
}}
onClick={() => {
removeData(item);
}}
>
<i class="bi bi-x text-danger"></i>
</div>
</div>
</>
);
})
) : (
<h3 style={{ textAlign: "center" }}>Cart is empety</h3>
)}
<div class="d-flex flex-row align-items-center mt-3 p-2 bg-white rounded">
<input
type="text"
class="form-control gift-card "
placeholder="discount code/gift card"
/>
<button
class="btn btn-sm ml-3 shadow"
type="button"
style={{
outline: "#3EC1D5",
backgroundColor: "#3EC1D5",
color: "white",
}}
>
Apply
</button>
</div>
<div class="totalItems">
Total Items: <strong>12</strong>
</div>
<span class="TotalPrice">
Total price: <strong>12$</strong>
</span>
<div class="d-flex flex-row align-items-center mt-3 p-2 bg-white rounded">
<button
class="btn btn-block btn-sm ml-2 pay-button shadow"
type="button"
style={{ backgroundColor: "#3EC1D5" }}
>
Proceed to Pay
</button>
</div>
</div>
</div>
</div>
</>
);
};
export default Cart;
Try this for add:
let removeData = (e) => {
localStorage.setItem("name of the item") // e.target.name
};
There's alot going on in your site :)
I think it will be responsible to create a context, that will serve the cart to all other components.
Things to note here, (Found some little improvements)
Run the function in the useState hook, don't just leave it there like you did
When using Array.filter you need to return a boolean iorder for it too filter your array properly.
This is the code I brought up hope it helps you out.
CartContext.js file.
import React, { createContext, useContext, useEffect, useState } from "react";
export const CartContext = createContext();
function Cart({ children }) {
const arr = useCallback(() => {
let dat = localStorage.getItem("products");
if (dat) {
return JSON.parse(dat);
} else {
return [];
}
}, []);
const [productData, setproductData] = useState(() => arr());
const getJason = async () => {
try {
let fea = await fetch(
"https://script.google.com/macros/s/AKfycbxFCG7S-kjncQZwvcMnqq4wXoBAX8ecH1zkY2bLP7EE-YHlnKbiJ3RUuHtWLe6sIK30Kw/exec"
);
let acData = await fea.json();
// filter callback function should return a boolean. That is either true or false in order to make it work.
// SO i think this function isn't going to function properly
let itemsData = acData.shop.filter((element) => {
if (element.name) {
return element;
}
});
setbooksData(itemsData);
if (itemsData) {
croser.current.style.filter = "blur(0px)";
loding.current.style.display = "none";
}
} catch (error) {
croser.current.style.filter = "blur(0px)";
loding.current.style.display = "none";
}
};
// get product data from api
useEffect(() => {
getJason();
}, []);
const addProduct = (e) => {
// check if product id available on cart
const findProduct = productData.find((element) => {
return element.id === e.id;
});
// add first quantity if not available
if (!findProduct)
return setproductData([...productData, { ...e, quantity: 1 }]);
// increase quantity by 1
const newCart = productData.map((element) => {
return {
...element,
quantity: element.id === e.id ? element.quantity + 1 : element.quantity,
};
});
setproductData(newCart);
};
const removeProduct = (e) => {
// check if product id available on cart
const findProductQuantity = productData.find((element) => {
return element.id === e.id && element.quantity >= 1;
});
// add first quantity if not available
if (!findProduct)
// Your ui should prevent this
return;
// decrease quantity by 1
const reducedQuantityCart = productData.map((element) => {
return {
...element,
quantity: element.id === e.id ? element.quantity - 1 : element.quantity,
};
});
// filter out all products with quantity less than 1 (quantity : 0)
const newCart = productData.filter((element) => {
return element.quantity >= 1;
});
setproductData(newCart);
};
const deleteProduct = (e) => {
// check if product id available on cart
const findProduct = productData.find((element) => {
return element.id === e.id;
});
// add first quantity if not available
if (!findProduct)
// Your ui should prevent this
return;
const productIndex = productData.findIndex((element) => {
return element.id === e.id;
});
// splice (delete) product from the productData array
const newCart = [productData].splice(productIndex, 1);
setproductData(newCart);
};
const value = {
productData,
addProduct,
removeProduct,
deleteProduct,
};
return <CartContext.Provider value={value}>{children}</CartContext.Provider>;
}
In here you create a context, create all your function you will use to update your cart, and pass them to your Context provider
// create a hook can you use anywhere in the app
export const useCart = () => {
const context = useContext(CartContext);
if (!context) {
throw new Error("Must use useCart in CartContext Child");
}
const { productData, addProduct, removeProduct, deleteProduct } = context;
return { productData, addProduct, removeProduct, deleteProduct };
};
For this you create a custom hook that you can use inside any component provided it is a child of the Cart context. So make sure you wrap it all around your app
// Use Case
const SomeComponent = () => {
const { productData, addProduct, removeProduct } = useCart();
return (
<div>
<p> Number of Products: {productData.length}</p>
<div>
{productData?.map((product) => (
<div>
<p>{product?.name}</p>
<button onClick={() => addProduct(product)}>add</button>
<button onClick={() => removeProduct(product)}>
subtract/reduce
</button>
<button onClick={() => deleteProduct(product)}>delete</button>
</div>
))}
</div>
</div>
);
};
Use case Scenario od how this code will work. Hope you find this helful

How get fetch api data?

For example, when you press the science button, the information (author, date, title etc) of the science category should appear.
import React, { useState } from "react";
const App = () => {
const [state, setState] = useState([]);
const Category = [
"All",
"Business",
"Sports",
"World",
"Technology",
"Entertainment",
"Science",
];
const fetchValue = (category) => {
fetch(`https://inshorts-api.herokuapp.com/news?category=${category}`)
.then((res) => res.json())
.then((res) => setState(res.data));
};
const CategoryButton = ({ category }) => (
<button onClick={() => fetchValue(category)}> {category}</button>
);
return (
<>
<div className="d-flex">
{Category.map((value, index) => {
return <CategoryButton category={value} key={index} />;
})}
</div>
<br />
{state?.map((data) => {
return (
<div class="card">
<img src={data.imageUrl} alt="Avatar" style={{ width: "300px" }} />
<div class="container">
<h4>
<b>{data.author}</b>
</h4>
<p>{data.content}</p>
</div>
</div>
);
})}
</>
);
};
export default App;

React vertical Nested List open and close sub List

i have a react.js component in which i am displaying states and under i am displaying districts. To display this list it's working fine. The problem i want when i press any sates only that particular state sublist should display not all states sublist.
import React,{useState} from "react"
Const [open,,setOpen]=useState(false);
//Wrapper component
</div>
{states.map((city, index) => {
return <StateList state={state} key={index} />;
})}
</div>
//state component
<div onClick={()=>setOpen(!open)}>
<span >{state.name}</span>
<svg
viewBox="0 0 24 24"
className={`
${open ? "rotate-180" : ""}
`}
>
</svg>
</h2>
{open && <AreaList area={city} />}
</div>
//district component
const AreaList = ({ state }) => {
return state.districts.map((district) => (
<li>
<span className="ml-2 text-outer-space">
{district.name}
</span>
</li>
));
};
Here is working solution (without styles):
Codesandbox
import { useState } from "react";
const data = [
{
name: "Fujairah",
districts: [
{ name: "Al Buthna" },
{ name: "Al Bedia" },
{ name: "Town Center" },
{ name: "Wadi Al Sedr" }
]
},
{
name: "Abu Dhabi",
districts: [{ name: "Al Aman" }, { name: "Al Bahya" }]
}
];
const App = () => {
return (
<div>
{data.map((city) => {
return <City key={city.name} city={city} />;
})}
</div>
);
};
const City = ({ city }) => {
const [open, setOpen] = useState(false);
return (
<div onClick={() => setOpen(!open)}>
<h2>
<span>{city.name}</span>
</h2>
{open && <DistrictList city={city} />}
</div>
);
};
const DistrictList = ({ city }) => {
return city.districts.map((district) => (
<li key={district.name}>
<span>{district.name}</span>
</li>
));
};
export default App;

Cannot open modal when click the button

So, when i click the cart button, the modal should be open since i passed the openModal fuction down to the cart button, but when i click on the cart button, nothing happens, please help me to find out what wrong with my codes! Thank you so much!
context.js:
class ProductProvider extends React.Component {
state = {
products: storeProducts,
detailProduct: detailProduct,
cart: [],
modalOpen: false,
modalProduct: detailProduct
};
getItem = (id) => {
const product = this.state.products.find((item) => item.id === id);
return product;
};
addToCart = (id) => {
let tempProducts = [...this.state.products];
const index = tempProducts.indexOf(this.getItem(id));
const product = tempProducts[index];
product.inCart = true;
product.count = 1;
const price = product.price;
product.total = price;
this.setState(() => {
return (
{ products: tempProducts, cart: [...this.state.cart, product] },
() => console.log(this.state)
);
});
};
openModal = (id) => {
const product = this.getItem(id);
this.setState(() => {
return { modalProduct: product, openModal: true };
});
};
closeModal = (id) => {
this.setState(() => {
return { modalOpen: false };
});
};
render() {
return (
<ProductContext.Provider
value={{
...this.state,
addToCart: this.addToCart,
openModal: this.openModal,
closeModal: this.closeModal
}}
>
{this.props.children}
</ProductContext.Provider>
);
}
}
Product.js:
class Product extends React.Component {
render() {
const { id, title, img, price, inCart } = this.props.product;
return (
<ProductWrapper clasName="col-9 mx-auto col-md-6 col-lg-3 my-3">
<div className="card">
<ProductContext.Consumer>
{(value) => (
<div className="img-container p-5">
<Link to={`/details/${id}`}>
<img src={img} alt="product" className="card-img-top" />
</Link>
<button
className="cart-btn"
onClick={() => {
value.addToCart(id);
value.openModal(id);
}}
disabled={inCart ? true : false}
>
{inCart ? (
<p className="text-capitalize mb-0">In Cart</p>
) : (
<i class="fas fa-cart-plus"></i>
)}
</button>
</div>
)}
</ProductContext.Consumer>
<div className="card-footer d-flex justify-content-between">
<p className="align-self-center mb-0">{title}</p>
<h5 className="text-blue mb-0">
<span className="mr-1">$</span>
{price}
</h5>
</div>
</div>
</ProductWrapper>
);
}
}
Modal.js:
class Modal extends React.Component {
render() {
return (
<ProductConsumer>
{(value) => {
const { modalOpen, closeModal } = value;
const { img, title, price } = value.modalProduct;
if (!modalOpen) {
return null;
} else {
return (
<ModalContainer>
<div className="container">
<div className="row">
<div
className="col-8 mx-auto col-md-6 col-lg-4 p-5 text-center text-capitalize"
id="modal"
>
<h5>item added to cart</h5>
<img src={img} className="img-fluid" alt="" />
<h5>{title}</h5>
<h5 className="text-muted">price : ${price}</h5>
<Link to="/">
<ButtonContainer
onClick={() => {
closeModal();
}}
>
Continue Shopping
</ButtonContainer>
</Link>
<Link to="/cart">
<ButtonContainer
cart
onClick={() => {
closeModal();
}}
>
Go To Cart
</ButtonContainer>
</Link>
</div>
</div>
</div>
</ModalContainer>
);
}
}}
</ProductConsumer>
);
}
}
Sanbox link for better observation: https://codesandbox.io/s/why-cant-i-fetch-data-from-a-passed-value-forked-buz0u?file=/src/App.js

Cannot add item to cart when click on the button

When i click on the cart symbol, it changes its value to be in cart but actually my product is not rendered on the cart component, is there something wrong or missing in my code, please help me to fix it! Thank you so much!
Context.js:
class ProductProvider extends React.Component {
state = {
products: storeProducts,
detailProduct: detailProduct,
cart: [],
modalOpen: false,
modalProduct: detailProduct
};
getItem = (id) => {
const product = this.state.products.find((item) => item.id === id);
return product;
};
addToCart = (id) => {
console.log("add to cart");
let tempProducts = [...this.state.products];
const index = tempProducts.indexOf(this.getItem(id));
const product = tempProducts[index];
product.inCart = true;
product.count = 1;
const price = product.price;
product.total = price;
this.setState(() => {
return (
{ products: tempProducts, cart: [...this.state.cart, product] },
() => console.log(this.state)
);
});
};
openModal = (id) => {
const product = this.getItem(id);
this.setState(() => {
return { modalProduct: product, openModal: true };
});
};
closeModal = (id) => {
this.setState(() => {
return { modalOpen: false };
});
};
Cart.js:
import React from "react";
import CartColumns from "./CartColumns";
import CartList from "./CartList";
import EmptyCart from "./EmptyCart";
import { ProductContext } from "../App";
export default class Cart extends React.Component {
render() {
return (
<div>
<ProductContext.Consumer>
{(value) => {
console.log(value, "inside Product COnt");
if (value.length > 0) {
return (
<div>
<CartColumns />
<CartList items={items} />
</div>
);
} else {
<EmptyCart />;
}
}}
</ProductContext.Consumer>
</div>
);
}
}
CartList.js:
import React from "react";
import CartItem from "./CartItem";
export default function CartList(props) {
const { items } = props;
return (
<div>
{items.cart.map((item) => (
<CartItem
key={item.id}
item={item}
increment={item.increment}
decrement={item.decrement}
/>
))}
</div>
);
}
CartItem.js:
import React from "react";
function CartItem(props) {
const { id, title, img, price, total, count } = props.item;
const { increment, decrement, removeItem } = props;
return (
<div className="row my-1 text-capitalize text-center">
<div className="col-10 mx-auto col-lg-2">
<img
src={img}
style={{ width: "5rem", heigth: "5rem" }}
className="img-fluid"
alt=""
/>
</div>
<div className="col-10 mx-auto col-lg-2 ">
<span className="d-lg-none">product :</span> {title}
</div>
<div className="col-10 mx-auto col-lg-2 ">
<strong>
<span className="d-lg-none">price :</span> ${price}
</strong>
</div>
<div className="col-10 mx-auto col-lg-2 my-2 my-lg-0 ">
<div className="d-flex justify-content-center">
<div>
<span className="btn btn-black mx-1">-</span>
<span className="btn btn-black mx-1">{count}</span>
<span className="btn btn-black mx-1">+</span>
</div>
</div>
</div>
<div className="col-10 mx-auto col-lg-2 ">
<div className=" cart-icon">
<i className="fas fa-trash" />
</div>
</div>
<div className="col-10 mx-auto col-lg-2 ">
<strong>item total : ${total} </strong>
</div>
</div>
);
}
export default CartItem;
Sandbox link for better observation:https://codesandbox.io/s/cart-code-addict-forked-l6tfm?file=/src/cart/CartItem.js
There were few issues
Change following
this.setState(() => {
return (
{ products: tempProducts, cart: [...this.state.cart, product] },
() => console.log(this.state)
);
});
to
this.setState(
{
products: tempProducts,
cart: [...this.state.cart, product]
},
() => console.log(this.state)
);
And need to use value.cart to check for length and when passing as a prop.
Instead of
if (value.length > 0) {
return (
<div>
<CartColumns />
<CartList items={items} />
</div>
);
}
It should be
if (value.cart.length > 0) {
return (
<div>
<CartColumns />
<CartList items={value.cart} />
</div>
);
}
And in CartList,
Instead of
{
items.cart.map(item => (
<CartItem
key={item.id}
item={item}
increment={item.increment}
decrement={item.decrement}
/>
));
}
it should be
{
items.map(item => (
<CartItem
key={item.id}
item={item}
increment={item.increment}
decrement={item.decrement}
/>
));
}
Now it shows the cart with items
Code sandbox => https://codesandbox.io/s/cart-code-addict-forked-c3kug?file=/src/cart/CartList.js

Resources