diff --git a/.github/workflows/pipeline.yaml b/.github/workflows/pipeline.yaml index 6d77320..da06e9a 100644 --- a/.github/workflows/pipeline.yaml +++ b/.github/workflows/pipeline.yaml @@ -1,18 +1,18 @@ -name: 'pipeline' +name: "pipeline" on: push: branches: - - 'main' + - "main" pull_request: branches: - - 'main' + - "main" types: - - 'opened' - - 'synchronize' + - "opened" + - "synchronize" jobs: - deployment_pipeline: + backend_pipeline: runs-on: ubuntu-24.04 env: PORT: 3000 @@ -24,94 +24,136 @@ jobs: version: 10 - uses: actions/setup-node@v4 with: - node-version: '22' - + node-version: "22" - name: Installing dependencies - run: pnpm i --frozen-lockfile + run: pnpm i --recursive --frozen-lockfile + - name: Running linting run: pnpm lint - name: Running unit tests env: - TEST_URI: ${{ secrets.TEST_URI }} + TEST_URI: ${{ secrets.URI_TEST_BACKEND }} run: pnpm unitTest - - name: Installing frontend dependencies - run: pnpm i --frozen-lockfile - working-directory: ./Redux_FrontEnd + vanilla_pipeline: + needs: + - backend_pipeline + runs-on: ubuntu-24.04 + env: + PORT: 3000 + JWT_SECRET: ${{ secrets.JWT_SECRET }} + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 10 + - uses: actions/setup-node@v4 + with: + node-version: "22" + - name: Installing dependencies + run: pnpm i --recursive --frozen-lockfile + + - name: Running frontend linting + run: pnpm lint + working-directory: ./FrontEnd + - name: Running frontend unit tests + run: pnpm test + working-directory: ./FrontEnd + - name: Building frontend + run: pnpm build + working-directory: ./FrontEnd + + - name: Deploy to render + if: ${{ github.event_name == 'push' }} + run: curl https://api.render.com/deploy/srv-${{secrets.RENDER_VANILLA_SERVICE_ID}}?key=${{secrets.RENDER_API_KEY}} + + redux_pipeline: + needs: + - backend_pipeline + runs-on: ubuntu-24.04 + env: + PORT: 3000 + JWT_SECRET: ${{ secrets.JWT_SECRET }} + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 10 + - uses: actions/setup-node@v4 + with: + node-version: "22" + - name: Installing dependencies + run: pnpm i --recursive --frozen-lockfile + - name: Running frontend linting run: pnpm lint working-directory: ./Redux_FrontEnd - name: Running frontend unit tests - env: - TEST_URI: ${{ secrets.TEST_URI }} run: pnpm test working-directory: ./Redux_FrontEnd - name: Building frontend run: pnpm build working-directory: ./Redux_FrontEnd - - name: Installing E2E dependencies - run: pnpm i --frozen-lockfile - working-directory: ./E2E - name: Installing E2E browsers - run: npx playwright install chromium --with-deps + run: pnpx playwright install chromium --with-deps working-directory: ./E2E - name: Running E2E tests env: - TEST_URI: ${{ secrets.TEST_URI }} + TEST_URI: ${{ secrets.URI_TEST_REDUX }} run: pnpm test working-directory: ./E2E - + - name: Deploy to render if: ${{ github.event_name == 'push' }} - run: curl https://api.render.com/deploy/srv-${{secrets.RENDER_SERVICE_ID}}?key=${{secrets.RENDER_API_KEY}} - - - name: Send success notification - if: ${{ success() && github.event_name == 'push' }} - uses: stegzilla/discord-notify@v2 + run: curl https://api.render.com/deploy/srv-${{secrets.RENDER_REDUX_SERVICE_ID}}?key=${{secrets.RENDER_API_KEY}} + + query_pipeline: + needs: + - backend_pipeline + runs-on: ubuntu-24.04 + env: + PORT: 3000 + JWT_SECRET: ${{ secrets.JWT_SECRET }} + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 with: - webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }} - title: New build deployed - message: | - **Event:** ${{ github.event_name }} - **Repo:** ${{ github.event.repository.full_name }} - **Ref:** ${{ github.event.ref }} - **Workflow:** ${{ github.workflow }} - **Author:** ${{ github.event.head_commit.author.name }} - **Committer:** ${{ github.event.head_commit.committer.name }} - **Pusher:** ${{ github.event.pusher.name }} - **Pusher Date:** ${{ github.event.pusher.date }} - **Commit URL:** ${{ github.event.head_commit.url }} - **Commit Message:** ${{ github.event.head_commit.message }} - include_image: true - avatar_url: "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/9c870380-219a-4060-914d-9929082d5056/dfghzab-31509847-d454-4602-ac9b-0b1ad48ba9b7.png/v1/fill/w_600,h_600,q_80,strp/build_chan_by_lupinmk_dfghzab-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7ImhlaWdodCI6Ijw9NjAwIiwicGF0aCI6IlwvZlwvOWM4NzAzODAtMjE5YS00MDYwLTkxNGQtOTkyOTA4MmQ1MDU2XC9kZmdoemFiLTMxNTA5ODQ3LWQ0NTQtNDYwMi1hYzliLTBiMWFkNDhiYTliNy5wbmciLCJ3aWR0aCI6Ijw9NjAwIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmltYWdlLm9wZXJhdGlvbnMiXX0.PsmFPEaVbfDMhXGlNbGe7Jmku2lwgnw2blRzAxsKL-U" - username: BuildNotifier-chan - colour: "#32E638" - - name: Send failure notification - if: ${{ failure() && github.event_name == 'push' }} - uses: stegzilla/discord-notify@v2 + version: 10 + - uses: actions/setup-node@v4 with: - webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }} - title: New build failed - message: | - **Event:** ${{ github.event_name }} - **Repo:** ${{ github.event.repository.full_name }} - **Ref:** ${{ github.event.ref }} - **Workflow:** ${{ github.workflow }} - **Author:** ${{ github.event.head_commit.author.name }} - **Committer:** ${{ github.event.head_commit.committer.name }} - **Pusher:** ${{ github.event.pusher.name }} - **Pusher Date:** ${{ github.event.pusher.date }} - **Commit URL:** ${{ github.event.head_commit.url }} - **Commit Message:** ${{ github.event.head_commit.message }} - include_image: true - avatar_url: "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/9c870380-219a-4060-914d-9929082d5056/dfghzab-31509847-d454-4602-ac9b-0b1ad48ba9b7.png/v1/fill/w_600,h_600,q_80,strp/build_chan_by_lupinmk_dfghzab-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7ImhlaWdodCI6Ijw9NjAwIiwicGF0aCI6IlwvZlwvOWM4NzAzODAtMjE5YS00MDYwLTkxNGQtOTkyOTA4MmQ1MDU2XC9kZmdoemFiLTMxNTA5ODQ3LWQ0NTQtNDYwMi1hYzliLTBiMWFkNDhiYTliNy5wbmciLCJ3aWR0aCI6Ijw9NjAwIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmltYWdlLm9wZXJhdGlvbnMiXX0.PsmFPEaVbfDMhXGlNbGe7Jmku2lwgnw2blRzAxsKL-U" - username: BuildNotifier-chan - colour: "#F02E23" + node-version: "22" + - name: Installing dependencies + run: pnpm i --recursive --frozen-lockfile + + - name: Running frontend linting + run: pnpm lint + working-directory: ./ReactQuery_FrontEnd + - name: Running frontend unit tests + run: pnpm test + working-directory: ./ReactQuery_FrontEnd + - name: Building frontend + run: pnpm build + working-directory: ./ReactQuery_FrontEnd + + - name: Installing E2E browsers + run: pnpx playwright install chromium --with-deps + working-directory: ./E2E + - name: Running E2E tests + env: + TEST_URI: ${{ secrets.URI_TEST_QUERY }} + run: pnpm test + working-directory: ./E2E + + - name: Deploy to render + if: ${{ github.event_name == 'push' }} + run: curl https://api.render.com/deploy/srv-${{secrets.RENDER_QUERY_SERVICE_ID}}?key=${{secrets.RENDER_API_KEY}} tag_release: needs: - - deployment_pipeline + - vanilla_pipeline + - redux_pipeline + - query_pipeline runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 @@ -121,3 +163,101 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} DEFAULT_BUMP: patch + + +# deployment_pipeline: +# runs-on: ubuntu-24.04 +# env: +# PORT: 3000 +# JWT_SECRET: ${{ secrets.JWT_SECRET }} +# steps: +# - uses: actions/checkout@v4 +# - uses: pnpm/action-setup@v4 +# with: +# version: 10 +# - uses: actions/setup-node@v4 +# with: +# node-version: "22" +# +# - name: Installing dependencies +# run: pnpm i --frozen-lockfile +# - name: Running linting +# run: pnpm lint +# - name: Running unit tests +# env: +# TEST_URI: ${{ secrets.TEST_URI }} +# run: pnpm unitTest +# +# - name: Installing frontend dependencies +# run: pnpm i --frozen-lockfile +# working-directory: ./Redux_FrontEnd +# - name: Running frontend linting +# run: pnpm lint +# working-directory: ./Redux_FrontEnd +# - name: Running frontend unit tests +# env: +# test_uri: ${{ secrets.test_uri }} +# run: pnpm test +# working-directory: ./Redux_FrontEnd +# - name: Building frontend +# run: pnpm build +# working-directory: ./Redux_FrontEnd +# +# - name: Installing E2E dependencies +# run: pnpm i --frozen-lockfile +# working-directory: ./E2E +# - name: Installing E2E browsers +# run: pnpx playwright install chromium --with-deps +# working-directory: ./E2E +# - name: Running E2E tests +# env: +# TEST_URI: ${{ secrets.TEST_URI }} +# run: pnpm test +# working-directory: ./E2E +# +# - name: Deploy to render +# if: ${{ github.event_name == 'push' }} +# run: curl https://api.render.com/deploy/srv-${{secrets.RENDER_SERVICE_ID}}?key=${{secrets.RENDER_API_KEY}} +# +# - name: Send success notification +# if: ${{ success() && github.event_name == 'push' }} +# uses: stegzilla/discord-notify@v2 +# with: +# webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }} +# title: New build deployed +# message: | +# **Event:** ${{ github.event_name }} +# **Repo:** ${{ github.event.repository.full_name }} +# **Ref:** ${{ github.event.ref }} +# **Workflow:** ${{ github.workflow }} +# **Author:** ${{ github.event.head_commit.author.name }} +# **Committer:** ${{ github.event.head_commit.committer.name }} +# **Pusher:** ${{ github.event.pusher.name }} +# **Pusher Date:** ${{ github.event.pusher.date }} +# **Commit URL:** ${{ github.event.head_commit.url }} +# **Commit Message:** ${{ github.event.head_commit.message }} +# include_image: true +# avatar_url: "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/9c870380-219a-4060-914d-9929082d5056/dfghzab-31509847-d454-4602-ac9b-0b1ad48ba9b7.png/v1/fill/w_600,h_600,q_80,strp/build_chan_by_lupinmk_dfghzab-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7ImhlaWdodCI6Ijw9NjAwIiwicGF0aCI6IlwvZlwvOWM4NzAzODAtMjE5YS00MDYwLTkxNGQtOTkyOTA4MmQ1MDU2XC9kZmdoemFiLTMxNTA5ODQ3LWQ0NTQtNDYwMi1hYzliLTBiMWFkNDhiYTliNy5wbmciLCJ3aWR0aCI6Ijw9NjAwIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmltYWdlLm9wZXJhdGlvbnMiXX0.PsmFPEaVbfDMhXGlNbGe7Jmku2lwgnw2blRzAxsKL-U" +# username: BuildNotifier-chan +# colour: "#32E638" +# - name: Send failure notification +# if: ${{ failure() && github.event_name == 'push' }} +# uses: stegzilla/discord-notify@v2 +# with: +# webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }} +# title: New build failed +# message: | +# **Event:** ${{ github.event_name }} +# **Repo:** ${{ github.event.repository.full_name }} +# **Ref:** ${{ github.event.ref }} +# **Workflow:** ${{ github.workflow }} +# **Author:** ${{ github.event.head_commit.author.name }} +# **Committer:** ${{ github.event.head_commit.committer.name }} +# **Pusher:** ${{ github.event.pusher.name }} +# **Pusher Date:** ${{ github.event.pusher.date }} +# **Commit URL:** ${{ github.event.head_commit.url }} +# **Commit Message:** ${{ github.event.head_commit.message }} +# include_image: true +# avatar_url: "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/9c870380-219a-4060-914d-9929082d5056/dfghzab-31509847-d454-4602-ac9b-0b1ad48ba9b7.png/v1/fill/w_600,h_600,q_80,strp/build_chan_by_lupinmk_dfghzab-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7ImhlaWdodCI6Ijw9NjAwIiwicGF0aCI6IlwvZlwvOWM4NzAzODAtMjE5YS00MDYwLTkxNGQtOTkyOTA4MmQ1MDU2XC9kZmdoemFiLTMxNTA5ODQ3LWQ0NTQtNDYwMi1hYzliLTBiMWFkNDhiYTliNy5wbmciLCJ3aWR0aCI6Ijw9NjAwIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmltYWdlLm9wZXJhdGlvbnMiXX0.PsmFPEaVbfDMhXGlNbGe7Jmku2lwgnw2blRzAxsKL-U" +# username: BuildNotifier-chan +# colour: "#F02E23" diff --git a/E2E/playwright.config.js b/E2E/playwright.config.js index 453bc63..c44afa9 100644 --- a/E2E/playwright.config.js +++ b/E2E/playwright.config.js @@ -69,7 +69,7 @@ module.exports = defineConfig({ /* Run your local dev server before starting the tests */ webServer: { - command: process.env.NODE_ENV === 'dev' ? 'cd .. && pnpm run test' : 'cd .. && npm run test', + command: process.env.NODE_ENV === 'dev' ? 'cd .. && pnpm test' : 'cd .. && npm test', url: `http://localhost:${process.env.PORT}` // reuseExistingServer: !process.env.CI, } diff --git a/FrontEnd/src/components/AccountForm.jsx b/FrontEnd/src/components/AccountForm.jsx index 73ea248..19a2a21 100644 --- a/FrontEnd/src/components/AccountForm.jsx +++ b/FrontEnd/src/components/AccountForm.jsx @@ -47,13 +47,13 @@ const AccountForm = ({ user, setUser, setError, setMessage, },) => { Username: - { setUsername(target.value,) }} name='username' type='text' /> + { setUsername(target.value,) }} name='username' placeholder='username' type='text' /> Password: - { setPassword(target.value,) }} name='password' type='password' /> + { setPassword(target.value,) }} name='password' placeholder='password' type='password' /> @@ -83,4 +83,4 @@ AccountForm.propType = { setMessage: PropTypes.func.isRequired, } -export default AccountForm \ No newline at end of file +export default AccountForm diff --git a/README.md b/README.md index 7b139a2..8dee497 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,12 @@ This project is a mini web application built with React, Vite, and Bootstrap. It - Rate system - Responsive design using Bootstrap. +## Lives + +- [Vanilla FrontEnd](https://minibloglistappvanilla.onrender.com "Just with states") +- [ Redux FrontEnd](https://minibloglistapp.onrender.com "Using reduxjs/toolkit") +- [ Query FrontEnd](https://minibloglistappquery.onrender.com "Using the react query lib and some contexts") + ## Getting Started ### Prerequisites @@ -24,11 +30,11 @@ This project is a mini web application built with React, Vite, and Bootstrap. It ### Fast Setup -- En Unix based +- In Unix based ```bash ./run.sh -- En windows +- In windows ```bash run.bat diff --git a/ReactQuery_FrontEnd/src/components/Blog.test.jsx b/ReactQuery_FrontEnd/src/components/Blog.test.jsx deleted file mode 100644 index d78b25b..0000000 --- a/ReactQuery_FrontEnd/src/components/Blog.test.jsx +++ /dev/null @@ -1,140 +0,0 @@ -import { render, screen } from '@testing-library/react' -import Blog from './Blog' -import { expect, vi } from 'vitest' -import userEvent from '@testing-library/user-event' - -const blogExample = { - title: 'Blog Title', - author: 'Author Name', - url: 'https://example.com', - likes: 10, - User: { - id: 'qwertyuiop', - username: 'username', - name: 'Name', - }, -} - -const userExample = { - id: 'qwertyuiop', - username: 'username', - name: 'Name', -} - -test('Details not visibles at first', () => { - const mockLikesHandler = vi.fn() - const mockRemoveHandler = vi.fn() - - render( - - ) - - const title = screen.getByText(blogExample.title) - expect(title).toBeVisible() - const author = screen.queryByText(blogExample.author) - expect(author).toBeVisible() - const url = screen.queryByText(blogExample.url) - expect(url).not.toBeVisible() - const likes = screen.queryByText(`likes ${blogExample.likes}`) - expect(likes).not.toBeVisible() - expect(mockLikesHandler.mock.calls).toHaveLength(0) - expect(mockRemoveHandler.mock.calls).toHaveLength(0) -}) - -test('Details visibles after click in show', async () => { - const mockLikesHandler = vi.fn() - const mockRemoveHandler = vi.fn() - - render( - - ) - - const user = userEvent.setup() - - const show = await screen.getByText('Show') - expect(show).toBeVisible() - await user.click(show) - const hide = await screen.getByText('Hide') - expect(hide).toBeVisible() - const title = screen.getByText(blogExample.title) - expect(title).toBeVisible() - const author = screen.queryByText(blogExample.author) - expect(author).toBeVisible() - const url = screen.queryByText(blogExample.url) - expect(url).toBeVisible() - const likes = screen.queryByText(`likes ${blogExample.likes}`) - expect(likes).toBeVisible() - expect(mockLikesHandler.mock.calls).toHaveLength(0) - expect(mockRemoveHandler.mock.calls).toHaveLength(0) -}) - -test('Details not visibles after click in hide', async () => { - const mockLikesHandler = vi.fn() - const mockRemoveHandler = vi.fn() - - render( - - ) - - const user = userEvent.setup() - - const show = await screen.getByText('Show') - expect(show).toBeVisible() - await user.click(show) - const hide = await screen.getByText('Hide') - expect(hide).toBeVisible() - await user.click(hide) - const title = screen.getByText(blogExample.title) - expect(title).toBeVisible() - const author = screen.queryByText(blogExample.author) - expect(author).toBeVisible() - const url = screen.queryByText(blogExample.url) - expect(url).not.toBeVisible() - const likes = screen.queryByText(`likes ${blogExample.likes}`) - expect(likes).not.toBeVisible() - expect(mockLikesHandler.mock.calls).toHaveLength(0) - expect(mockRemoveHandler.mock.calls).toHaveLength(0) -}) - -test('Twice click twice like', async () => { - const mockLikesHandler = vi.fn() - const mockRemoveHandler = vi.fn() - - render( - - ) - - const user = userEvent.setup() - - const show = await screen.getByText('Show') - expect(show).toBeVisible() - await user.click(show) - const likes = screen.queryByText(`likes ${blogExample.likes}`) - expect(likes).toBeVisible() - const giveLike = screen.getByText('like') - expect(giveLike).toBeVisible() - await user.click(giveLike) - await user.click(giveLike) - expect(mockLikesHandler.mock.calls).toHaveLength(2) - expect(mockRemoveHandler.mock.calls).toHaveLength(0) -}) diff --git a/ReactQuery_FrontEnd/src/providers/notifications.jsx b/ReactQuery_FrontEnd/src/providers/notifications.jsx index 4d0e303..602e792 100644 --- a/ReactQuery_FrontEnd/src/providers/notifications.jsx +++ b/ReactQuery_FrontEnd/src/providers/notifications.jsx @@ -1,5 +1,5 @@ import { useReducer, } from 'react' -import { notificationReducer } from '../contexts/notification' +import { notificationReducer, } from '../contexts/notification' import notificationContext from '../contexts/notification' diff --git a/ReactQuery_FrontEnd/src/providers/user.jsx b/ReactQuery_FrontEnd/src/providers/user.jsx index dc07535..ea8b424 100644 --- a/ReactQuery_FrontEnd/src/providers/user.jsx +++ b/ReactQuery_FrontEnd/src/providers/user.jsx @@ -1,5 +1,5 @@ import { useReducer, } from 'react' -import { userReducer } from '../contexts/user' +import { userReducer, } from '../contexts/user' import userContext from '../contexts/user'