Skip to content

Commit

Permalink
Merge pull request #914 from w3bdesign/dev
Browse files Browse the repository at this point in the history
Add test for products
  • Loading branch information
w3bdesign authored May 31, 2023
2 parents 71356cc + 55a4fc0 commit 160c5be
Show file tree
Hide file tree
Showing 7 changed files with 237 additions and 14 deletions.
35 changes: 29 additions & 6 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ orbs:
browser-tools: circleci/[email protected]

jobs: # a collection of steps
build: # runs not using Workflows must have a `build` job as entry point
dusk: # runs not using Workflows must have a `build` job as entry point
docker: # run the steps with Docker
#- image: cimg/php:8.0.14-browsers # ...with this image as the primary container; this is where all `steps` will run
- image: cimg/php:8.2.4-browsers # ...with this image as the primary container; this is where all `steps` will run
auth:
username: mydockerhub-user
password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
working_directory: ~/laravel # directory where steps will run
steps: # a set of executable commands
- checkout # special step to check out source code to working directory
Expand Down Expand Up @@ -45,14 +44,38 @@ jobs: # a collection of steps
- run:
name: Serve Application
background: true
command: php artisan serve
command: php artisan serve
- run: php artisan dusk
- run: php artisan test
- run: php artisan test
- store_artifacts:
path: ./tests/Browser/console
destination: console
- store_artifacts:
path: ./tests/Browser/screenshots
destination: screenshots
# See https://circleci.com/docs/2.0/deployment-integrations/ for deploy examples
resource_class: large
resource_class: large

vue-tests:
docker:
- image: cimg/node:16.5.0
working_directory: ~/laravel
steps:
- checkout
- restore_cache:
keys:
- node-v1-{{ checksum "package-lock.json" }}
- node-v1-
- run: npm ci
- save_cache:
key: node-v1-{{ checksum "package-lock.json" }}
paths:
- node_modules
- run: npm run test # Assuming you have a "test" script in your package.json for running Vue tests

workflows:
version: 2
build-and-test:
jobs:
- dusk
- vue-tests
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Ecommerce site with Laravel 10, Vue 3 and Stripe.

- SonarCloud code quality scanner integration on all pull requests

- Laravel tests with CircleCI integration
- Laravel Dusk and Jest tests with CircleCI integration

## Main dependencies:

Expand Down Expand Up @@ -101,8 +101,6 @@ Ecommerce site with Laravel 10, Vue 3 and Stripe.

- Do WCAG analysis and ensure there are no issues

- Add some tests to verify that the cart and checkout works correctly

- Consider adding an admin dashboard

- Look into performance optimization
5 changes: 2 additions & 3 deletions tests/Browser/ExampleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ public function testBasicExample()
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
//->screenshot('home-page')
->assertSee('MacBook');
//->assertPathIs('/');
->assertSee('MacBook')
->assertPathIs('/');
});
}
}
1 change: 0 additions & 1 deletion tests/Vue/Button/button.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import BaseButton from "../../../resources/js/components/base/BaseButton.vue";
import "@testing-library/jest-dom";

test("Verify that the button renders and that the default slot works", async () => {
// The render method returns a collection of utilities to query your component.
const { getByText } = render(BaseButton, {
slots: { default: "Button test" },
});
Expand Down
12 changes: 11 additions & 1 deletion tests/Vue/LoadingSpinner/loadingspinner.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
// https://github.com/testing-library/vue-testing-library/tree/main/src/__tests__
import { render } from "@testing-library/vue";
import BaseLoadingSpinner from "../../../resources/js/components/base/BaseLoadingSpinner.vue";

import "@testing-library/jest-dom";

test("Verify that the loading message is rendered", async () => {
const { getByText } = render(BaseLoadingSpinner);

const loadingMessage = getByText("Loading products ...");
expect(loadingMessage).toBeInTheDocument();
});
102 changes: 102 additions & 0 deletions tests/Vue/Products/ShowallProducts.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { render } from "@testing-library/vue";
import ShowAllProducts from "../../../resources/js/components/Products/ShowAllProducts.vue";
import formatPrice from "../../../resources/js/utils/functions";

import "@testing-library/jest-dom";

jest.mock("swrv", () => ({
__esModule: true,
default: jest.fn(),
}));

const useRouterLink = {
template: "<a><slot></slot></a>",
};

/**
* @description
* Test case to verify that products are rendered correctly with their respective details,
* and that the router-link component works as expected.
*
* The test will:
* 1. Mock the `useSWRV` hook to return a list of products.
* 2. Render the `ShowAllProducts` component.
* 3. Iterate through each product and check if the product's name, price, and image are present in the DOM.
* 4. Check if the list of images found by the role "img" matches the length of the products list.
*
* @async
* @function
* @name verifyProductsAreRenderedAndRouterLinkWorksTest
*/
test("Verify products are rendered and router-link works", async () => {
const useSWRV = require("swrv").default;
const products = [
{
id: 1,
name: "Product 1",
price: 100,
slug: "product-1",
imageUrl: "image1.jpg",
},
{
id: 2,
name: "Product 2",
price: 200,
slug: "product-2",
imageUrl: "image2.jpg",
},
];
useSWRV.mockReturnValue({ data: products, error: null });

const { getByText, getAllByRole } = render(ShowAllProducts, {
global: {
components: {
"router-link": useRouterLink,
},
},
});

for (const product of products) {
expect(getByText(product.name)).toBeInTheDocument();
expect(getByText(formatPrice(product.price))).toBeInTheDocument();

const productLink = getByText(product.name).closest("a");
const productImage = productLink.querySelector("img");
expect(productImage).toHaveAttribute("src", product.imageUrl);
}

const images = getAllByRole("img");
expect(images.length).toBe(products.length);
});

/**
* @description
* Test case to verify that an error message is displayed when an error occurs while loading products.
*
* The test will:
* 1. Mock the `useSWRV` hook to return an error.
* 2. Render the `ShowAllProducts` component.
* 3. Check if the error message is present in the DOM.
*
* @async
* @function
* @name verifyErrorMessageIsDisplayedWhenErrorOccursTest
*/
test("Verify error message is displayed when error occurs", async () => {
const useSWRV = require("swrv").default;
useSWRV.mockReturnValue({
data: null,
error: new Error("Error loading products"),
});

const { getByText } = render(ShowAllProducts, {
global: {
components: {
"router-link": useRouterLink,
},
},
});

const errorMessage = getByText("Error loading products");
expect(errorMessage).toBeInTheDocument();
});
92 changes: 92 additions & 0 deletions tests/Vue/Products/SingleProduct.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { fireEvent, render } from "@testing-library/vue";

import SingleProduct from "../../../resources/js/components/Products/SingleProduct.vue";
import { useCart } from "../../../resources/js/store/useCart";
import formatPrice from "../../../resources/js/utils/functions";

import "@testing-library/jest-dom";

jest.mock("swrv", () => ({
__esModule: true,
default: jest.fn(),
}));

// Mock the useCart function
jest.mock("@/store/useCart", () => {
const addToCartMock = jest.fn();
return {
useCart: jest.fn(() => ({ addToCart: addToCartMock })),
__addToCartMock: addToCartMock,
};
});

// Mock the useRoute function
jest.mock("vue-router", () => ({
useRoute: jest.fn(() => ({
params: {
slug: "product-1",
},
})),
}));

const useRouterLink = {
template: "<a><slot></slot></a>",
};

/**
* Test case to verify the 'Add to Cart' functionality.
*
* @name Verify 'Add to Cart' functionality
* @function
* @async
* @memberof module:tests
*
* @description
* The test case does the following:
* 1. Mocks the `useSWRV` hook to return the product data.
* 2. Mocks the `useCart` store to use a Jest function as the `addToCart` method.
* 3. Renders the `SingleProduct` component with the necessary global components.
* 4. Verifies the product information is displayed.
* 5. Clicks the 'Add To Cart' button.
* 6. Verifies that the `addToCart` method in the store is called with the correct product.
*
* @returns {void}
*/
test("Verify 'Add to Cart' functionality", async () => {
const useSWRV = require("swrv").default;
const product = {
id: 1,
name: "Product 1",
price: 100,
slug: "product-1",
imageUrl: "image1.jpg",
description: "Sample description",
};
useSWRV.mockReturnValue({ data: product, error: null });

const addToCartMock = jest.fn();
useCart.mockReturnValue({
addToCart: addToCartMock,
});

const { getByText } = render(SingleProduct, {
global: {
components: {
"router-link": useRouterLink,
},
},
});

// Verify product information is displayed
expect(getByText(product.name)).toBeInTheDocument();
expect(getByText(formatPrice(product.price))).toBeInTheDocument();
expect(getByText(product.description)).toBeInTheDocument();

// Click the 'Add To Cart' button
const addToCartButton = getByText("Add To Cart");
await fireEvent.click(addToCartButton);

// Verify that the `addToCart` method in the store is called with the correct product
expect(addToCartMock).toHaveBeenCalledTimes(1);
expect(addToCartMock).toHaveBeenCalledWith({ item: product });
});

0 comments on commit 160c5be

Please sign in to comment.