Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit test to Header component and create CI workflow #199

Merged
merged 29 commits into from
Jun 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0308946
Add unit test to Header component and create CI workflow
zehguilherme Jun 22, 2023
363b528
Add "enter web folder" step
zehguilherme Jun 22, 2023
822a6d8
Remove empty line
zehguilherme Jun 22, 2023
0d95256
Update install dependencies command
zehguilherme Jun 22, 2023
f0c47a1
Update enter web folder step
zehguilherme Jun 22, 2023
fbbc99b
Update command to web folder
zehguilherme Jun 22, 2023
4cca2aa
Update install dependencies step
zehguilherme Jun 22, 2023
cf3e459
Update yarn commands
zehguilherme Jun 22, 2023
aa5c5ac
Update install dependencies step
zehguilherme Jun 23, 2023
e09d8d5
Update install dependencies command
zehguilherme Jun 23, 2023
5a50bde
Add enter web folder step
zehguilherme Jun 23, 2023
f54241e
Update lint step
zehguilherme Jun 23, 2023
c8ad451
Integrate enter web folder in install dependencies
zehguilherme Jun 23, 2023
7e62e4b
Add node setup
zehguilherme Jun 23, 2023
7536ce0
Change enter project folder step before setup node step
zehguilherme Jun 24, 2023
384ccbe
Change eslint command to external action
zehguilherme Jun 24, 2023
aa30c09
Add eslint install
zehguilherme Jun 24, 2023
6ec225f
Return eslint to self command
zehguilherme Jun 24, 2023
944c506
Fix yarn step
zehguilherme Jun 24, 2023
e4ef009
Add test command
zehguilherme Jun 24, 2023
1dbff0f
Change enter web folder step order
zehguilherme Jun 24, 2023
955916a
Update CI
zehguilherme Jun 24, 2023
fde80a0
Update eslint step
zehguilherme Jun 24, 2023
03862cb
Add new enter project folder step
zehguilherme Jun 25, 2023
61d6f11
Replace enter project folder step by working-directory
zehguilherme Jun 25, 2023
a7df554
Add lint fix step
zehguilherme Jun 25, 2023
be7bad6
Add new rule
zehguilherme Jun 25, 2023
334078d
Fix eslint and prettier problems
zehguilherme Jun 25, 2023
07903ba
Add new rule
zehguilherme Jun 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: "[CI] Continuous Integration"

on:
pull_request:
types: [opened, synchronize]

jobs:
lint:
runs-on: ubuntu-latest

steps:
- name: Repository Checkout
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: v18.x
- name: Install Dependencies
working-directory: ./web
run: yarn install
- name: Lint
working-directory: ./web
run: yarn lint
- name: Lint Fix
working-directory: ./web
run: yarn lint:fix

test:
runs-on: ubuntu-latest

steps:
- name: Repository Checkout
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: v18.x
- name: Install Dependencies
working-directory: ./web
run: yarn install
- name: Test - Jest
working-directory: ./web
run: yarn test
36 changes: 36 additions & 0 deletions web/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
plugins: ["react", "prettier", "jest"],
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:jest/recommended",
"plugin:react/jsx-runtime",
"plugin:prettier/recommended",
],
overrides: [],
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
settings: {
react: {
version: "detect",
},
},
ignorePatterns: ["node_modules/"],
rules: {
"no-console": "error",
"react/no-unknown-property": ["error", { ignore: ["jsx", "global"] }],
"jest/no-disabled-tests": "warn",
"jest/no-focused-tests": "error",
"jest/no-identical-title": "error",
"jest/prefer-to-have-length": "warn",
"jest/valid-expect": "error",
"prettier/prettier": 0,
},
};
3 changes: 0 additions & 3 deletions web/.eslintrc.json

This file was deleted.

3 changes: 3 additions & 0 deletions web/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"editorconfig": true
}
19 changes: 19 additions & 0 deletions web/jest.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// jest.config.mjs
import nextJest from "next/jest.js";

const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: "./",
});

// Add any custom config to be passed to Jest
/** @type {import('jest').Config} */
const config = {
// Add more setup options before each test is run
setupFilesAfterEnv: ["@testing-library/jest-dom/extend-expect"],

testEnvironment: "jest-environment-jsdom",
};

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
export default createJestConfig(config);
12 changes: 6 additions & 6 deletions web/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'www.datocms-assets.com',
protocol: "https",
hostname: "www.datocms-assets.com",
},
],
},
experimental: {
scrollRestoration: true
}
}
scrollRestoration: true,
},
};

module.exports = nextConfig
module.exports = nextConfig;
22 changes: 19 additions & 3 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
"lint": "eslint \"./**/*.{js,jsx,ts,tsx}\"",
"lint:fix": "yarn lint -- --fix",
"test:watch": "jest --watchAll",
"test": "jest"
},
"dependencies": {
"@vercel/analytics": "^1.0.0",
"@vercel/og": "^0.5.1",
"eslint": "8.36.0",
"eslint-config-next": "13.2.4",
"graphql": "^16.6.0",
"graphql-request": "^5.2.0",
"next": "13.2.4",
Expand All @@ -23,9 +24,24 @@
"yet-another-react-lightbox": "^3.2.0"
},
"devDependencies": {
"@testing-library/dom": "^9.2.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"autoprefixer": "^10.4.14",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jest": "^27.2.2",
"eslint-plugin-n": "^16.0.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.32.2",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"postcss": "^8.4.21",
"prettier": "^2.8.8",
"prettier-plugin-tailwindcss": "^0.3.0",
"tailwindcss": "^3.2.7"
}
}
2 changes: 1 addition & 1 deletion web/postcss.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ module.exports = {
tailwindcss: {},
autoprefixer: {},
},
}
};
3 changes: 3 additions & 0 deletions web/prettier.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
plugins: [require("prettier-plugin-tailwindcss")],
};
70 changes: 70 additions & 0 deletions web/src/components/Header/Header.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import { Header } from ".";
import { Hamburguer } from "../icons/Hamburger";
import { Logo } from "../icons/Logo";
import { Xmark } from "../icons/Xmark";

describe("Header component", () => {
it("should render a h1 title", () => {
render(<Header />);

const header1 = screen.getByText("Studio Amanda Borges");
expect(header1).toHaveClass("sr-only");
expect(header1).toBeInTheDocument();
});

it("should render a link to the Home page", () => {
render(<Header />);

const homeLink = screen.getByLabelText("Navegar para a página Home");
expect(homeLink).toHaveAttribute("href", "/");
expect(homeLink).toBeInTheDocument();
});

it("should render a logo svg", () => {
const { container } = render(<Logo />);

const logoElement = container.querySelector("svg");
expect(logoElement).toHaveAttribute("name", "logo");
expect(logoElement).toBeVisible();
expect(logoElement).toBeInTheDocument();
});

it("should render a button with a X mark icon or Hamburger icon", async () => {
const user = userEvent.setup();

render(<Header />);

const navMenuButton = screen.getByRole("button");
expect(navMenuButton).toHaveAttribute("name", "menu-button");
expect(navMenuButton).toHaveAttribute("type", "button");
expect(navMenuButton).toBeInTheDocument();

await user.click(navMenuButton);

const { container: hamburger } = render(<Hamburguer />);
const hamburgerElement = hamburger.querySelector("svg");
expect(hamburgerElement).toHaveAttribute("name", "hamburger");
expect(hamburgerElement).toBeVisible();

await user.click(navMenuButton);

const { container: xMark } = render(<Xmark />);
const xMarkElement = xMark.querySelector("svg");
expect(xMarkElement).toHaveAttribute("name", "x-mark");
expect(xMarkElement).toBeVisible();
});

it("should render 4 links with their correctly styles", () => {
render(<Header />);

const links = screen.getAllByRole("link");

links.forEach((link) => {
expect(link).toHaveAttribute("href");
expect(link).toBeInTheDocument();
});
});
});
81 changes: 81 additions & 0 deletions web/src/components/Header/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/* eslint-disable react/prop-types */
import Link from "next/link";

import { Hamburguer } from "@/components/icons/Hamburger";
import { Logo } from "@/components/icons/Logo";
import { Xmark } from "@/components/icons/Xmark";

export function Header({ navMenuIsOpened, handleNavMenuChange }) {
return (
<header className="bg-pink">
<div
className={
navMenuIsOpened
? "container mx-auto pb-6 lg:flex lg:items-center lg:justify-between lg:p-0"
: "container mx-auto lg:flex lg:items-center lg:justify-between lg:p-0"
}
>
<div className="flex items-center justify-between pr-6 text-white-white1 lg:flex-none lg:p-0">
<h1 className="sr-only">Studio Amanda Borges</h1>

<Link href="/" aria-label="Navegar para a página Home">
<Logo className="w-[150px]" />
</Link>

<button
type="button"
className="lg:hidden"
name="menu-button"
aria-label={`${
navMenuIsOpened ? "Botão contendo a letra X" : "Botão hambúrguer"
}`}
onClick={handleNavMenuChange}
>
{navMenuIsOpened ? (
<Xmark className="w-12" aria-expanded="true" />
) : (
<Hamburguer className="w-12" aria-expanded="false" />
)}
</button>
</div>

<nav className={navMenuIsOpened ? "block" : "hidden lg:block"}>
<ul className="text-white-white1 lg:flex lg:px-6 lg:py-5">
<li className="text-lg font-bold">
<Link
href="/"
className="flex h-12 items-center justify-center px-6 duration-100 hover:opacity-50 hover:transition-all lg:h-11 lg:hover:border-b lg:hover:opacity-100"
>
Home
</Link>
</li>
<li className="text-lg font-bold">
<a
href="#projetos"
className="flex h-12 items-center justify-center px-6 duration-100 hover:opacity-50 hover:transition-all lg:h-11 lg:hover:border-b lg:hover:opacity-100"
>
Projetos
</a>
</li>
<li className="text-lg font-bold">
<a
href="#sobre"
className="flex h-12 items-center justify-center px-6 duration-100 hover:opacity-50 hover:transition-all lg:h-11 lg:hover:border-b lg:hover:opacity-100"
>
Sobre
</a>
</li>
<li className="text-lg font-bold">
<a
href="#contato"
className="flex h-12 items-center justify-center px-6 duration-100 hover:opacity-50 hover:transition-all lg:h-11 lg:hover:border-b lg:hover:opacity-100"
>
Contato
</a>
</li>
</ul>
</nav>
</div>
</header>
);
}
1 change: 1 addition & 0 deletions web/src/components/LightboxNextJsImage/index.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable react/prop-types */
import Image from "next/image";
import {
isImageFitCover,
Expand Down
9 changes: 5 additions & 4 deletions web/src/components/ProjectCard/index.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable react/prop-types */
import Image from "next/image";
import Link from "next/link";

Expand All @@ -17,15 +18,15 @@ export function ProjectCard({
height={351}
placeholder="blur"
blurDataURL={imgUrl}
className="aspect-square rounded-[5px] object-center object-cover"
className="aspect-square rounded-[5px] object-cover object-center"
/>

<div className="flex flex-col items-start space-y-1 p-6 w-full bg-gradient-to-t from-gray-900 absolute bottom-0">
<h3 className="text-white-white1 text-xl font-bold break-all">
<div className="absolute bottom-0 flex w-full flex-col items-start space-y-1 bg-gradient-to-t from-gray-900 p-6">
<h3 className="break-all text-xl font-bold text-white-white1">
{projectTitle}
</h3>

<span className="text-white-white1 text-base">{projectYear}</span>
<span className="text-base text-white-white1">{projectYear}</span>
</div>
</Link>
);
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/ScrollUpButton/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function ScrollUpButton() {

return (
<button
className={`rounded-full text-center p-3 bg-gray-200 hover:bg-gray-200/75 fixed bottom-5 right-4 text-black ${
className={`fixed bottom-5 right-4 rounded-full bg-gray-200 p-3 text-center text-black hover:bg-gray-200/75 ${
visible ? "block" : "hidden"
}`}
onClick={() => scrollToTop()}
Expand Down
1 change: 1 addition & 0 deletions web/src/components/icons/Hamburger.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export function Hamburguer(props) {
viewBox="0 0 48 48"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
name="hamburger"
{...props}
>
<path
Expand Down
1 change: 1 addition & 0 deletions web/src/components/icons/Logo.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export function Logo(props) {
x="0px"
y="0px"
viewBox="0 0 1500 1500"
name="logo"
{...props}
>
<path
Expand Down
1 change: 1 addition & 0 deletions web/src/components/icons/Xmark.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export function Xmark(props) {
viewBox="0 0 48 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
name="x-mark"
{...props}
>
<path
Expand Down
Loading