diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d76e417..b9dcc17 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,21 +13,28 @@ jobs: steps: - name: Checkout PROD uses: actions/checkout@v4 + - name: Install Node.js latest uses: actions/setup-node@v4 with: node-version: latest check-latest: true + - name: Install dependencies run: npm ci + - name: Run ESLint - run: npx eslint --no-error-on-unmatched-pattern . + run: npx eslint --no-error-on-unmatched-pattern. + + - name: Run all tests + run: npm run test + - name: Generate build env: CI: false run: npm run build - # Share artifact inside workflow + # Share artifact - name: Share artifact inside workflow uses: actions/upload-artifact@v4 with: @@ -38,4 +45,4 @@ jobs: uses: ncipollo/release-action@v1.14.0 with: artifacts: "react-github-actions-build" - tag: v1.5.4.7 \ No newline at end of file + tag: v1.5.5 \ No newline at end of file diff --git a/README.md b/README.md index 53691c5..79bc75c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@

- Studio Zed project made with React Js
+ A Studio Zed project made with React Js
+ Feel free to use it as a template for your own projects!
Visit Studio Zed! [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) @@ -50,5 +51,21 @@ This project was built using these technologies. - Run `serve -s build` to serve the optimized build. - From the terminal, you can see the local address & network address to view the build, copy and paste it in your browser. +## Running tests +- Run `npm run test` to run tests. +- There are 1 test suite and 5 tests in total. +- Testing setup can be found in `setupTests.js` & all tests are in `App.test.js`. +- Tests are written using Jest & React Testing Library. +- All 5 Tests are currently integrated into the `CI/CD` pipeline. +- Example of when all tests pass: +```bash + PASS src/App.test.js + ✓ Test home page content (50 ms) + ✓ Find contact form (69 ms) + ✓ Find form submit button (11 ms) + ✓ Test web vitals (1 ms) + ✓ Test AboutPage (15 ms) + ``` + ## Known Issues -- Security issues found in dependencies but are low risk to this project, See dependabot alert [#26](https://github.com/OudomMunint/StudioZed-ReactJS/security/dependabot/26) and alert [#12](https://github.com/OudomMunint/StudioZed-ReactJS/security/dependabot/12) +- Security issues found in dependencies but are low risk to this project, See dependabot alert [#26](https://github.com/OudomMunint/StudioZed-ReactJS/security/dependabot/26), alert [#12](https://github.com/OudomMunint/StudioZed-ReactJS/security/dependabot/12) and [#27](https://github.com/OudomMunint/StudioZed-ReactJS/security/dependabot/27). \ No newline at end of file diff --git a/src/App.test.js b/src/App.test.js index 1f03afe..dd7260b 100644 --- a/src/App.test.js +++ b/src/App.test.js @@ -1,8 +1,57 @@ import { render, screen } from '@testing-library/react'; import App from './App'; +import ContactForm from './components/Contact'; +import reportWebVitals from "./reportWebVitals"; +import About from './components/About/About'; -test('renders learn react link', () => { +// Test home page content +test('Test home page content', () => { render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); + const linkElement1 = screen.getByText(/Welcome!/i); + const linkElement2 = screen.getByText(/We are/i); + const linkElements3 = screen.getAllByText(/Studio Zed/i); + + expect(linkElement1).toBeInTheDocument(); + expect(linkElement2).toBeInTheDocument(); + expect(linkElements3.length).toBeGreaterThan(0); // If atleast 1 match. }); + +// Test contact form +test('Find contact form', async () => { + render(); + const formTitle = await screen.findByText(/Get in touch!/i); + const formFieldName = await screen.findByPlaceholderText(/Name/i); + const formFieldEmail = await screen.findByPlaceholderText(/Email/i); + const formFieldMessage = await screen.findByPlaceholderText(/Message/i); + + expect(formTitle).toBeInTheDocument(); + expect(formFieldName).toBeInTheDocument(); + expect(formFieldEmail).toBeInTheDocument(); + expect(formFieldMessage).toBeInTheDocument(); +}); + +// Test form submit button +test('Find form submit button', () => { + render(); + const submitButton = screen.getByRole('button', { name: /Submit/i }); + expect(submitButton).toBeInTheDocument(); +}); + +// Test web vitals +test('Test web vitals', () => { + reportWebVitals(metric => { + console.log('Web Vitals metric:', metric); + expect(metric).toBeDefined(); + expect(metric.name).toBeTruthy(); + }); +}); + +// Test if about page is rendered +test('Test AboutPage', () => { + render(); + const aboutPage = About(); + if (aboutPage != null) { + console.log("About page is rendered"); + } + expect(aboutPage).not.toBeNull(); +}); \ No newline at end of file diff --git a/src/components/Contact.js b/src/components/Contact.js index e96b4cf..06f9372 100644 --- a/src/components/Contact.js +++ b/src/components/Contact.js @@ -1,12 +1,11 @@ -import React, { useState } from "react"; +import React, { useState, useEffect, useCallback } from "react"; function ContactForm() { const isDevelopment = process.env.NODE_ENV === "development"; const [name, setName] = useState(""); const [email, setEmail] = useState(""); const [message, setMessage] = useState(""); - - const handleSubmit = async (event) => { + const handleSubmit = useCallback(async (event) => { event.preventDefault(); let data = { name, email, message }; try { @@ -14,31 +13,33 @@ function ContactForm() { setName(''); setEmail(''); setMessage(''); - data = { name: "testUser1", email: "test@test.com", message: "Hello, this is a test message." }; - console.log('Form submission successful:'); - console.log(data); + if (isDevelopment) { + data = { + name: "testUser1", + email: "test@test.com", + message: "Hello, this is a test message." + }; + } + console.log('Form submission successful:', data); } catch (error) { console.error('Form submission error:', error); console.log('Error caught'); } - }; + }, [name, email, message, isDevelopment]); - if (isDevelopment) { - try { - document.getElementsByClassName("submit").addEventListener("click", handleSubmit); - } - catch (error) { - console.error('Error:', error); - } - } - else { - try { - document.getElementsByClassName("submit").removeEventListener("click", handleSubmit); - } - catch (error) { - console.error('Error:', error); + useEffect(() => { + if (isDevelopment) { + const button = document.querySelector(".submit"); + if (button) { + button.addEventListener("click", handleSubmit); + } + return () => { + if (button) { + button.removeEventListener("click", handleSubmit); + } + }; } - } + }, [isDevelopment, handleSubmit]); return ( <> @@ -84,7 +85,7 @@ function ContactForm() {
{/* Submit */} - diff --git a/src/components/Footer.js b/src/components/Footer.js index 7704cdd..88b2d3a 100644 --- a/src/components/Footer.js +++ b/src/components/Footer.js @@ -21,7 +21,7 @@ function Footer() {