Skip to content

Commit

Permalink
Merge pull request #87 from OudomMunint/dev
Browse files Browse the repository at this point in the history
PR: Dev => Main
  • Loading branch information
OudomMunint authored Aug 17, 2024
2 parents 16b36a7 + 709786d commit 683d05f
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 57 deletions.
13 changes: 10 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -38,4 +45,4 @@ jobs:
uses: ncipollo/[email protected]
with:
artifacts: "react-github-actions-build"
tag: v1.5.4.7
tag: v1.5.5
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<h2 align="center">
Studio Zed project made with React Js<br/>
A Studio Zed project made with React Js<br/>
Feel free to use it as a template for your own projects!<br/>
<a href="https://studiozed.netlify.app/" target="_blank">Visit Studio Zed!</a>

[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
Expand Down Expand Up @@ -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).
55 changes: 52 additions & 3 deletions src/App.test.js
Original file line number Diff line number Diff line change
@@ -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(<App />);
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(<ContactForm />);
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(<ContactForm />);
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(<About />);
const aboutPage = About();
if (aboutPage != null) {
console.log("About page is rendered");
}
expect(aboutPage).not.toBeNull();
});
47 changes: 24 additions & 23 deletions src/components/Contact.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,45 @@
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 {
// clear form
setName('');
setEmail('');
setMessage('');
data = { name: "testUser1", email: "[email protected]", message: "Hello, this is a test message." };
console.log('Form submission successful:');
console.log(data);
if (isDevelopment) {
data = {
name: "testUser1",
email: "[email protected]",
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 (
<>
Expand Down Expand Up @@ -84,7 +85,7 @@ function ContactForm() {
</div>
<div data-netlify-recaptcha="true" className="reCaptcha"></div>
{/* Submit */}
<button className="btn btn-danger submit" type="submit" style={{ position: "relative", marginTop: "68px" }}>
<button title="submit" className="btn btn-danger submit" type="submit" style={{ position: "relative", marginTop: "68px" }}>
Submit
</button>
</form>
Expand Down
8 changes: 4 additions & 4 deletions src/components/Footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function Footer() {
<ul className="footer-icons">
<li className="social-icons">
<a
href="#"
href="/#"
style={{ color: "white" }}
target="_blank"
rel="noopener noreferrer"
Expand All @@ -31,7 +31,7 @@ function Footer() {
</li>
<li className="social-icons">
<a
href="#"
href="/#"
style={{ color: "white" }}
target="_blank"
rel="noopener noreferrer"
Expand All @@ -41,7 +41,7 @@ function Footer() {
</li>
<li className="social-icons">
<a
href="#"
href="/#"
style={{ color: "white" }}
target="_blank"
rel="noopener noreferrer"
Expand All @@ -51,7 +51,7 @@ function Footer() {
</li>
<li className="social-icons">
<a
href="#"
href="/#"
style={{ color: "white" }}
target="_blank"
rel="noopener noreferrer"
Expand Down
31 changes: 18 additions & 13 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";

// Main component
ReactDOM.render(
<React.StrictMode>
<App />
Expand All @@ -13,17 +14,21 @@ ReactDOM.render(

const isDevelopment = process.env.NODE_ENV === "development";

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);

if (isDevelopment) {
reportWebVitals(console.log);
}
// Web Vitals
// TODO: Send metrics to an analytics endpoint
// if (isDevelopment) {
// reportWebVitals(console.log);
// } else {
// reportWebVitals(metric => {
// fetch('/api/analytics', {
// method: 'POST',
// body: JSON.stringify(metric),
// headers: { 'Content-Type': 'application/json' }
// }).catch(err => console.error('Error reporting Web Vitals:', err));
// });
// }

else {
console.log("Web vitals report generation is disabled in production");
}
// Web Vitals
reportWebVitals(metric => {
console.log('Web Vitals metric:', metric);
});
24 changes: 15 additions & 9 deletions src/reportWebVitals.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
//Web vitals! Do not remove!
// Web vitals
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
import('web-vitals')
.then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
try {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
} catch (error) {
console.error('Error collecting Web Vitals:', error);
}
})
.catch(error => console.error('Error loading Web Vitals library:', error));
}
};

export default reportWebVitals;
export default reportWebVitals;

0 comments on commit 683d05f

Please sign in to comment.