Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8518f46
Add backend api written in rust
saisab29 Dec 24, 2024
2a0e39e
Fetch project from the database in the home page instead of data.json
saisab29 Dec 24, 2024
9739da2
Fetch data of each project page from backend
saisab29 Dec 26, 2024
2bede7e
Fetch similar projects from backend
saisab29 Dec 26, 2024
a515823
Restarting backend
saisab29 Dec 26, 2024
d981f03
Added backend folder
saisab29 Dec 26, 2024
39c4774
Backup setup including sql migrations and composefile for container
saisab29 Dec 27, 2024
4f4ad47
Updated backend api url for fretch from environment vaiiable
saisab29 Dec 27, 2024
6fa799f
Updated test for frontend component
saisab29 Dec 31, 2024
fef6194
Updated docker compose file for building compose stack including fron…
saisab29 Dec 31, 2024
0ec9948
Test id property for test
saisab29 Dec 31, 2024
4826d1f
Publish compose stack to ghcr
saisab29 Dec 31, 2024
b9e0aca
Update stack to ghcr
saisab29 Dec 31, 2024
dd797f3
Used docker-compose-dev.yml
saisab29 Dec 31, 2024
ec9a22f
direct image builds using docker/build-push-action
saisab29 Dec 31, 2024
98fe4a0
use docker build instead of docker compose build
saisab29 Dec 31, 2024
8d7ac3b
without generate stack attestation
saisab29 Dec 31, 2024
22fc92b
Create ghcr images with build args
saisab29 Jan 2, 2025
1477293
backend image rebuild
saisab29 Jan 2, 2025
5d2959e
Updated docker file for backend
saisab29 Jan 2, 2025
aeee571
Updated migrations for database
saisab29 Jan 2, 2025
503e0a0
Updated workflow for publishing ghcr image
saisab29 Jan 3, 2025
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
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.git
.gitignore
Dockerfile
node_modules/
**/__tests__
97 changes: 97 additions & 0 deletions .github/workflows/publish-ghcr-stack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: Create and publish Docker Compose stack to ghcr

on:
workflow_run:
workflows: ["Run Tests"]
types:
- completed

env:
REGISTRY: ghcr.io
BACKEND_IMAGE_NAME: ${{ github.repository }}-backend
FRONTEND_IMAGE_NAME: ${{ github.repository }}-frontend

jobs:
build-and-push-images:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Get latest tag and commit distance
id: get_version_info
run: |
# Get the latest tag
LATEST_TAG=$(git describe --tags --abbrev=0)

# Remove 'v' prefix from latest tag
BASE_VERSION=${LATEST_TAG#v}

# Get the number of commits since the last tag
COMMIT_DISTANCE=$(git rev-list --count ${LATEST_TAG}..HEAD)

# Construct new version with build number
NEW_VERSION="${BASE_VERSION}.${COMMIT_DISTANCE}"

echo "version=${NEW_VERSION}" >> $GITHUB_OUTPUT
echo "Generated version: ${NEW_VERSION}"

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

# Build and push backend image
- name: Extract metadata for Backend
id: meta-backend
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}
tags: |
type=raw,value=${{ steps.get_version_info.outputs.version }}
type=raw,value=latest

- name: Build and push Backend image
id: push-backend
uses: docker/build-push-action@v5
with:
context: ./backend/api
file: ./backend/api/Dockerfile
push: true
tags: ${{ steps.meta-backend.outputs.tags }}
labels: ${{ steps.meta-backend.outputs.labels }}
build-args: |
DATABASE_URL=postgresql://admin:saisab@postgres:5432/rust_sqlx?schema=public

# Build and push frontend image
- name: Extract metadata for Frontend
id: meta-frontend
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}
tags: |
type=raw,value=${{ steps.get_version_info.outputs.version }}
type=raw,value=latest

- name: Build and push Frontend image
id: push-frontend
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta-frontend.outputs.tags }}
labels: ${{ steps.meta-frontend.outputs.labels }}
build-args: |
API_URL=http://backend:8000
NODE_ENV=production
75 changes: 0 additions & 75 deletions .github/workflows/publish-ghcr.yml

This file was deleted.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

/target
163 changes: 33 additions & 130 deletions __tests__/Home.test.tsx
Original file line number Diff line number Diff line change
@@ -1,143 +1,46 @@
import { render, screen, fireEvent } from "@testing-library/react";
import Home from "../src/app/page";
// __tests__/Home.test.tsx
import { render, screen } from "@testing-library/react";
import Home from "@/app/page";
import "@testing-library/jest-dom";

// Mock data (assuming 10 projects for pagination test)
jest.mock("../src/data.json", () => [
// Mock fetch
global.fetch = jest.fn();

const mockProjects = [
{
id: "1",
projectName: "Project 1",
imageUrl: "/path/to/image1.jpg",
subImageUrl: "/path/to/subimage1.jpg",
projectname: "Project 1",
projecturl: "#",
imageurl: "/path/to/image1.jpg",
subimageurl: "/path/to/subimage1.jpg",
description: "Description 1",
url: "#",
},
{
id: "2",
projectName: "Project 2",
imageUrl: "/path/to/image2.jpg",
subImageUrl: "/path/to/subimage2.jpg",
description: "Description 2",
url: "#",
},
{
id: "3",
projectName: "Project 3",
imageUrl: "/path/to/image3.jpg",
subImageUrl: "/path/to/subimage3.jpg",
description: "Description 3",
url: "#",
},
{
id: "4",
projectName: "Project 4",
imageUrl: "/path/to/image4.jpg",
subImageUrl: "/path/to/subimage4.jpg",
description: "Description 4",
url: "#",
},
{
id: "5",
projectName: "Project 5",
imageUrl: "/path/to/image5.jpg",
subImageUrl: "/path/to/subimage5.jpg",
description: "Description 5",
url: "#",
about: "About 1",
createdAt: "2024-01-01",
published: true,
updatedAt: "2024-01-01",
},
{
id: "6",
projectName: "Project 6",
imageUrl: "/path/to/image6.jpg",
subImageUrl: "/path/to/subimage6.jpg",
description: "Description 6",
url: "#",
},
{
id: "7",
projectName: "Project 7",
imageUrl: "/path/to/image7.jpg",
subImageUrl: "/path/to/subimage7.jpg",
description: "Description 7",
url: "#",
},
{
id: "8",
projectName: "Project 8",
imageUrl: "/path/to/image8.jpg",
subImageUrl: "/path/to/subimage8.jpg",
description: "Description 8",
url: "#",
},
{
id: "9",
projectName: "Project 9",
imageUrl: "/path/to/image9.jpg",
subImageUrl: "/path/to/subimage9.jpg",
description: "Description 9",
url: "#",
},
]);
];

describe("Home Page", () => {
test("renders the correct number of cards for the current page", () => {
render(<Home />);

// Initially, it should show the first 8 cards (cards per page = 8)
const cards = screen.getAllByRole("link");
expect(cards).toHaveLength(8);

// Check the first card's text
expect(screen.getByText("Project 1")).toBeInTheDocument();
});

test("renders 2nd page correctly when Next is clicked", () => {
render(<Home />);

// Click Next to go to the second page
const nextButton = screen.getByText("Next");
fireEvent.click(nextButton);

// It should now show cards 9 and 10
const cards = screen.getAllByRole("link");
expect(cards).toHaveLength(1); // Since there are only 9 cards, the second page will have only 1 card.

expect(screen.getByText("Project 9")).toBeInTheDocument();
});

test("disables the Previous button on the first page", () => {
render(<Home />);

// The Previous button should be disabled on the first page
const prevButton = screen.getByText("Previous");
expect(prevButton).toBeDisabled();
beforeEach(() => {
(global.fetch as jest.Mock).mockResolvedValue({
ok: true,
json: async () => ({
projects: mockProjects,
results: mockProjects.length,
status: "success",
}),
});
});

test("disables the Next button on the last page", () => {
render(<Home />);

let nextButton = screen.getByText("Next") as HTMLButtonElement;

// Loop until the Next button becomes disabled
while (!nextButton.disabled) {
fireEvent.click(nextButton);
nextButton = screen.getByText("Next") as HTMLButtonElement;
}

// Once on the last page, the Next button should be disabled
expect(nextButton).toBeDisabled();
it("renders the page", async () => {
render(await Home());
expect(screen.getByText("Project 1")).toBeInTheDocument();
});

test("navigates correctly when page numbers are clicked", () => {
render(<Home />);

// Check if the second page button is clickable
const page2Button = screen.getByText("2");
fireEvent.click(page2Button);

// After clicking the page 2 button, it should show the next set of cards
const cards = screen.getAllByRole("link");
expect(cards).toHaveLength(1); // Since there are only 9 cards, the second page will have 1 card.

expect(screen.getByText("Project 9")).toBeInTheDocument();
});
// it("handles API error gracefully", async () => {
// (global.fetch as jest.Mock).mockRejectedValueOnce(new Error("API Error"));
// render(await Home());
// expect(screen.getByText("No projects available.")).toBeInTheDocument();
// });
});
Loading
Loading