diff --git a/.github/FUNDING.yml b/.github/FUNDING.y
similarity index 100%
rename from .github/FUNDING.yml
rename to .github/FUNDING.y
diff --git a/.github/actionlint.yaml b/.github/actionlint.ya
similarity index 100%
rename from .github/actionlint.yaml
rename to .github/actionlint.ya
diff --git a/.github/labeler.yml b/.github/labeler.y
similarity index 100%
rename from .github/labeler.yml
rename to .github/labeler.y
diff --git a/.github/workflow/cron-translations.yml b/.github/workflow/cron-translations.yml
new file mode 100644
index 0000000000000..e776a0d5dc713
--- /dev/null
+++ b/.github/workflow/cron-translations.yml
@@ -0,0 +1,38 @@
+# name: cron-translations
+
+# on:
+# schedule:
+# - cron: "7 0 * * *" # every day at 00:07 UTC
+# workflow_dispatch:
+
+# jobs:
+# crowdin-pull:
+# runs-on: ubuntu-latest
+# if: github.repository == 'go-gitea/gitea'
+# steps:
+# - uses: actions/checkout@v4
+# - uses: crowdin/github-action@v1
+# with:
+# upload_sources: true
+# upload_translations: false
+# download_sources: false
+# download_translations: true
+# push_translations: false
+# push_sources: false
+# create_pull_request: false
+# config: crowdin.yml
+# env:
+# CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
+# CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
+# - name: update locales
+# run: ./build/update-locales.sh
+# - name: push translations to repo
+# uses: appleboy/git-push-action@v0.0.3
+# with:
+# author_email: "teabot@gitea.io"
+# author_name: GiteaBot
+# branch: main
+# commit: true
+# commit_message: "[skip ci] Updated translations via Crowdin"
+# remote: "git@github.com:go-gitea/gitea.git"
+# ssh_key: ${{ secrets.DEPLOY_KEY }}
diff --git a/.github/workflows/Pre-Production.yml b/.github/workflows/Pre-Production.yml
new file mode 100644
index 0000000000000..32fb398a41663
--- /dev/null
+++ b/.github/workflows/Pre-Production.yml
@@ -0,0 +1,37 @@
+name: Pre-Production Performance Testing
+
+on:
+ push:
+ branches:
+ - main # Runs after PR is merged into main
+
+jobs:
+ preprod-perf-test:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Set up Java (required by JMeter)
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'temurin'
+ java-version: '21'
+
+ - name: Install JMeter
+ run: |
+ sudo apt update
+ sudo apt install -y jmeter
+ jmeter --version
+
+ - name: Run JMeter Test
+ run: |
+ mkdir -p reports/jmeter
+ jmeter -n -t tests/perf_test.jmx -l reports/jmeter/results.jtl -e -o reports/jmeter/report
+
+ - name: Upload JMeter HTML Report
+ uses: actions/upload-artifact@bcb6a651d2b8c4fdb17bcf0d2581a3ad16f58aa9 # Pin to known good SHA
+ with:
+ name: jmeter-report
+ path: reports/jmeter/report
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000000000..deb5c945815ab
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,66 @@
+name: Gitea Build Environment Workflow
+
+on:
+ push:
+ branches:
+ - feature_branch
+ # Trigger on push to the dev branch just
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ # Step 1: Checkout the code from the repository
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ # Step 2: Set up Go (Gitea is written in Go) yes yesy se
+ - name: Set up Go
+ uses: actions/setup-go@v2
+ with:
+ go-version: '1.24.0' # Use the Go version that Gitea supports
+
+ # Step 3: Install dependencies
+ - name: Install dependencies
+ run: go mod tidy
+
+ - name: Run unit tests
+ run: go test ./... -v
+ continue-on-error: true
+
+ - name: Run linting
+ run: |
+ go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
+ golangci-lint run
+ continue-on-error: true
+
+ docker:
+ runs-on: ubuntu-latest
+ needs: build # This will wait until the 'build' job is finished
+
+ steps:
+ # Step 1: Checkout the repository
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ # Step 2: Set up Docker
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
+ # Step 3: Log in to Docker Hub
+ - name: Log in to Docker Hub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }} # Store your Docker username as a secret in GitHub
+ password: ${{ secrets.DOCKER_PASSWORD }} # Store your Docker password as a secret in GitHub
+
+ # Step 4: Build the Docker image
+ - name: Build Docker image
+ run: |
+ docker build -t maias816/gitea:latest .
+
+ # Step 5: Push the Docker image to Docker Hub
+ - name: Push Docker image
+ run: |
+ docker push maias816/gitea:latest
diff --git a/.github/workflows/cron-licenses.yml b/.github/workflows/cron-licenses.yml
index 33cbc507d9677..c392a0e4982ef 100644
--- a/.github/workflows/cron-licenses.yml
+++ b/.github/workflows/cron-licenses.yml
@@ -1,8 +1,35 @@
+# name: cron-licenses
+
+# on:
+# # schedule:
+# # - cron: "7 0 * * 1" # every Monday at 00:07 UTC
+# workflow_dispatch:
+
+# jobs:
+# cron-licenses:
+# runs-on: ubuntu-latest
+# if: github.repository == 'go-gitea/gitea'
+# steps:
+# - uses: actions/checkout@v4
+# - uses: actions/setup-go@v5
+# with:
+# go-version-file: go.mod
+# check-latest: true
+# - run: make generate-license generate-gitignore
+# timeout-minutes: 40
+# - name: push translations to repo
+# uses: appleboy/git-push-action@v0.0.3
+# with:
+# author_email: "teabot@gitea.io"
+# author_name: GiteaBot
+# branch: main
+# commit: true
+# commit_message: "[skip ci] Updated licenses and gitignores"
+# remote: "git@github.com:go-gitea/gitea.git"
+# ssh_key: ${{ secrets.DEPLOY_KEY }}
name: cron-licenses
on:
- # schedule:
- # - cron: "7 0 * * 1" # every Monday at 00:07 UTC
workflow_dispatch:
jobs:
diff --git a/.github/workflows/cron-translations.yml b/.github/workflows/cron-translations.yml
deleted file mode 100644
index f1b51debf1223..0000000000000
--- a/.github/workflows/cron-translations.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-name: cron-translations
-
-on:
- schedule:
- - cron: "7 0 * * *" # every day at 00:07 UTC
- workflow_dispatch:
-
-jobs:
- crowdin-pull:
- runs-on: ubuntu-latest
- if: github.repository == 'go-gitea/gitea'
- steps:
- - uses: actions/checkout@v4
- - uses: crowdin/github-action@v1
- with:
- upload_sources: true
- upload_translations: false
- download_sources: false
- download_translations: true
- push_translations: false
- push_sources: false
- create_pull_request: false
- config: crowdin.yml
- env:
- CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
- CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
- - name: update locales
- run: ./build/update-locales.sh
- - name: push translations to repo
- uses: appleboy/git-push-action@v0.0.3
- with:
- author_email: "teabot@gitea.io"
- author_name: GiteaBot
- branch: main
- commit: true
- commit_message: "[skip ci] Updated translations via Crowdin"
- remote: "git@github.com:go-gitea/gitea.git"
- ssh_key: ${{ secrets.DEPLOY_KEY }}
diff --git a/.github/workflows/files-changed.yml b/.github/workflows/files-changed.yml
index 7c1fb024421bc..60bbb085bf38c 100644
--- a/.github/workflows/files-changed.yml
+++ b/.github/workflows/files-changed.yml
@@ -1,3 +1,101 @@
+# name: files-changed
+
+# on:
+# workflow_call:
+# outputs:
+# backend:
+# value: ${{ jobs.detect.outputs.backend }}
+# frontend:
+# value: ${{ jobs.detect.outputs.frontend }}
+# docs:
+# value: ${{ jobs.detect.outputs.docs }}
+# actions:
+# value: ${{ jobs.detect.outputs.actions }}
+# templates:
+# value: ${{ jobs.detect.outputs.templates }}
+# docker:
+# value: ${{ jobs.detect.outputs.docker }}
+# swagger:
+# value: ${{ jobs.detect.outputs.swagger }}
+# yaml:
+# value: ${{ jobs.detect.outputs.yaml }}
+
+# jobs:
+# detect:
+# runs-on: ubuntu-latest
+# timeout-minutes: 3
+# outputs:
+# backend: ${{ steps.changes.outputs.backend }}
+# frontend: ${{ steps.changes.outputs.frontend }}
+# docs: ${{ steps.changes.outputs.docs }}
+# actions: ${{ steps.changes.outputs.actions }}
+# templates: ${{ steps.changes.outputs.templates }}
+# docker: ${{ steps.changes.outputs.docker }}
+# swagger: ${{ steps.changes.outputs.swagger }}
+# yaml: ${{ steps.changes.outputs.yaml }}
+# steps:
+# - uses: actions/checkout@v4
+# - uses: dorny/paths-filter@v3
+# id: changes
+# with:
+# filters: |
+# backend:
+# - "**/*.go"
+# - "templates/**/*.tmpl"
+# - "assets/emoji.json"
+# - "go.mod"
+# - "go.sum"
+# - "Makefile"
+# - ".golangci.yml"
+# - ".editorconfig"
+# - "options/locale/locale_en-US.ini"
+
+# frontend:
+# - "**/*.js"
+# - "web_src/**"
+# - "assets/emoji.json"
+# - "package.json"
+# - "package-lock.json"
+# - "Makefile"
+# - ".eslintrc.yaml"
+# - "stylelint.config.js"
+# - ".npmrc"
+
+# docs:
+# - "**/*.md"
+# - ".markdownlint.yaml"
+# - "package.json"
+# - "package-lock.json"
+
+# actions:
+# - ".github/workflows/*"
+# - "Makefile"
+
+# templates:
+# - "tools/lint-templates-*.js"
+# - "templates/**/*.tmpl"
+# - "pyproject.toml"
+# - "poetry.lock"
+
+# docker:
+# - "Dockerfile"
+# - "Dockerfile.rootless"
+# - "docker/**"
+# - "Makefile"
+
+# swagger:
+# - "templates/swagger/v1_json.tmpl"
+# - "Makefile"
+# - "package.json"
+# - "package-lock.json"
+# - ".spectral.yaml"
+
+# yaml:
+# - "**/*.yml"
+# - "**/*.yaml"
+# - ".yamllint.yaml"
+# - "pyproject.toml"
+# - "poetry.lock"
name: files-changed
on:
diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
new file mode 100644
index 0000000000000..2c7c10f78d3ca
--- /dev/null
+++ b/.github/workflows/integration-tests.yml
@@ -0,0 +1,56 @@
+name: Gitea Setup and Testing
+
+on:
+ pull_request:
+
+
+ workflow_dispatch:
+
+jobs:
+ setup-and-test:
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13
+ options: --health-cmd="pg_isready -U gitea_user" --health-timeout=30s --health-retries=3
+ ports:
+ - 5432:5432
+ env:
+ POSTGRES_DB: gitea
+ POSTGRES_USER: gitea_user
+ POSTGRES_PASSWORD: gitea_pass
+
+ redis:
+ image: redis:alpine
+ ports:
+ - 6379:6379
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Log in to Docker Hub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }} # GitHub Secrets for Docker username
+ password: ${{ secrets.DOCKER_PASSWORD }} # GitHub Secrets for Docker password
+
+ - name: Pull Test Docker Image for API tests
+ run: |
+ docker pull maias816/api_ui_tests:latest
+ # Pull the existing image from docker hub1
+ - name: Run API and UI Tests
+ run: |
+ docker run --rm maias816/api_ui_tests:latest
+
+ # - name: pull feature image # pull and feature image ok k
+ # run: |
+ # docker pull maias816/code-formatter:latest
+ # - name : run feature tests
+ # run: |
+ # docker run maias816/code-formatter:latest
+
+
+
+
diff --git a/.golangci.yml b/.golangci.yml
index c39d7ac5f2f5b..67560db4b902c 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -37,9 +37,11 @@ output:
linters-settings:
testifylint:
- disable:
- - go-require
- - require-error
+ disable:
+ - go-require
+ - require-error
+
+
stylecheck:
checks: ["all", "-ST1005", "-ST1003"]
nakedret:
diff --git a/MaiasREADME.md b/MaiasREADME.md
new file mode 100644
index 0000000000000..4010e161ae96d
--- /dev/null
+++ b/MaiasREADME.md
@@ -0,0 +1,102 @@
+
+# π³ Run Gitea using Docker
+
+This guide explains how to run **Gitea**, a self-hosted Git service, using **Docker**.
+
+---
+
+## β
1. Install Docker
+
+Download and install Docker from the official website:
+π [https://www.docker.com/products/docker-desktop](https://www.docker.com/products/docker-desktop)
+
+---
+
+## β
2. Create Required Folders
+
+Create directories for persistent Gitea data:
+
+### On Linux / macOS:
+```bash
+mkdir -p ~/gitea/{data,config}
+```
+
+### On Windows PowerShell:
+```powershell
+mkdir gitea\data
+mkdir gitea\config
+```
+
+---
+
+## β
3. Run Gitea Docker Container
+
+Use this command to run Gitea with **SQLite** (simplest setup):
+
+```bash
+docker run -d --name=gitea \
+ -p 3000:3000 -p 222:22 \
+ -v ~/gitea/data:/data \
+ gitea/gitea:latest
+```
+
+- `-p 3000:3000`: maps web interface to `http://localhost:3000`
+- `-p 222:22`: maps SSH (optional)
+- `-v ~/gitea/data:/data`: mounts persistent data volume
+
+> β οΈ On Windows, use full path like `C:/Users/YourName/gitea/data` instead of `~/gitea/data`.
+
+---
+
+## β
4. Access Gitea mm
+
+After a few seconds, go to:
+```
+http://localhost:3000
+```
+
+Follow the setup wizard:
+- Choose **SQLite** (or MySQL/PostgreSQL)
+- Set admin user credentials
+- Complete setup
+
+---
+
+## β
5. (Optional) Docker Compose Setup
+
+Create a `docker-compose.yml` file:
+
+```yaml
+version: "3"
+
+services:
+ gitea:
+ image: gitea/gitea:latest
+ container_name: gitea
+ environment:
+ - USER_UID=1000
+ - USER_GID=1000
+ restart: always
+ volumes:
+ - ./gitea/data:/data
+ ports:
+ - "3000:3000"
+ - "222:22"
+```
+
+Then run:
+
+```bash
+docker-compose up -d
+```
+
+---
+
+## β
Common URLs
+
+- Web UI: `http://localhost:3000`
+- SSH (if enabled): `ssh -p 222 git@localhost`
+
+---
+
+Let me know if you want to use a specific database (e.g. MySQL, PostgreSQL) or encounter any issues.
diff --git a/README.md b/README.md
index f747d993d7984..5852f44639f52 100644
--- a/README.md
+++ b/README.md
@@ -1,159 +1 @@
-# Gitea
-
-[](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
-[](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
-[](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card")
-[](https://pkg.go.dev/code.gitea.io/gitea "GoDoc")
-[](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
-[](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
-[](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
-[](https://opensource.org/licenses/MIT "License: MIT")
-[](https://gitpod.io/#https://github.com/go-gitea/gitea)
-[](https://translate.gitea.com "Crowdin")
-
-[View this document in Chinese](./README_ZH.md)
-
-## Purpose
-
-The goal of this project is to make the easiest, fastest, and most
-painless way of setting up a self-hosted Git service.
-
-As Gitea is written in Go, it works across **all** the platforms and
-architectures that are supported by Go, including Linux, macOS, and
-Windows on x86, amd64, ARM and PowerPC architectures.
-This project has been
-[forked](https://blog.gitea.com/welcome-to-gitea/) from
-[Gogs](https://gogs.io) since November of 2016, but a lot has changed.
-
-For online demonstrations, you can visit [demo.gitea.com](https://demo.gitea.com).
-
-For accessing free Gitea service (with a limited number of repositories), you can visit [gitea.com](https://gitea.com/user/login).
-
-To quickly deploy your own dedicated Gitea instance on Gitea Cloud, you can start a free trial at [cloud.gitea.com](https://cloud.gitea.com).
-
-## Documentation
-
-You can find comprehensive documentation on our official [documentation website](https://docs.gitea.com/).
-
-It includes installation, administration, usage, development, contributing guides, and more to help you get started and explore all features effectively.
-
-If you have any suggestions or would like to contribute to it, you can visit the [documentation repository](https://gitea.com/gitea/docs)
-
-## Building
-
-From the root of the source tree, run:
-
- TAGS="bindata" make build
-
-or if SQLite support is required:
-
- TAGS="bindata sqlite sqlite_unlock_notify" make build
-
-The `build` target is split into two sub-targets:
-
-- `make backend` which requires [Go Stable](https://go.dev/dl/), the required version is defined in [go.mod](/go.mod).
-- `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater.
-
-Internet connectivity is required to download the go and npm modules. When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js.
-
-More info: https://docs.gitea.com/installation/install-from-source
-
-## Using
-
-After building, a binary file named `gitea` will be generated in the root of the source tree by default. To run it, use:
-
- ./gitea web
-
-> [!NOTE]
-> If you're interested in using our APIs, we have experimental support with [documentation](https://docs.gitea.com/api).
-
-## Contributing
-
-Expected workflow is: Fork -> Patch -> Push -> Pull Request
-
-> [!NOTE]
->
-> 1. **YOU MUST READ THE [CONTRIBUTORS GUIDE](CONTRIBUTING.md) BEFORE STARTING TO WORK ON A PULL REQUEST.**
-> 2. If you have found a vulnerability in the project, please write privately to **security@gitea.io**. Thanks!
-
-## Translating
-
-[](https://translate.gitea.com)
-
-Translations are done through [Crowdin](https://translate.gitea.com). If you want to translate to a new language ask one of the managers in the Crowdin project to add a new language there.
-
-You can also just create an issue for adding a language or ask on discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord. For general translation questions there is a section in the docs. Currently a bit empty but we hope to fill it as questions pop up.
-
-Get more information from [documentation](https://docs.gitea.com/contributing/localization).
-
-## Official and Third-Party Projects
-
-We provide an official [go-sdk](https://gitea.com/gitea/go-sdk), a CLI tool called [tea](https://gitea.com/gitea/tea) and an [action runner](https://gitea.com/gitea/act_runner) for Gitea Action.
-
-We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea), where you can discover more third-party projects, including SDKs, plugins, themes, and more.
-
-## Communication
-
-[](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
-
-If you have questions that are not covered by the [documentation](https://docs.gitea.com/), you can get in contact with us on our [Discord server](https://discord.gg/Gitea) or create a post in the [discourse forum](https://forum.gitea.com/).
-
-## Authors
-
-- [Maintainers](https://github.com/orgs/go-gitea/people)
-- [Contributors](https://github.com/go-gitea/gitea/graphs/contributors)
-- [Translators](options/locale/TRANSLATORS)
-
-## Backers
-
-Thank you to all our backers! π [[Become a backer](https://opencollective.com/gitea#backer)]
-
-
-
-## Sponsors
-
-Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/gitea#sponsor)]
-
-
-
-
-
-
-
-
-
-
-
-
-## FAQ
-
-**How do you pronounce Gitea?**
-
-Gitea is pronounced [/Ι‘Ιͺβti:/](https://youtu.be/EM71-2uDAoY) as in "gi-tea" with a hard g.
-
-**Why is this not hosted on a Gitea instance?**
-
-We're [working on it](https://github.com/go-gitea/gitea/issues/1029).
-
-**Where can I find the security patches?**
-
-In the [release log](https://github.com/go-gitea/gitea/releases) or the [change log](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md), search for the keyword `SECURITY` to find the security patches.
-
-## License
-
-This project is licensed under the MIT License.
-See the [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) file
-for the full license text.
-
-## Further information
-
-
-Looking for an overview of the interface? Check it out!
-
-||||
-|:---:|:---:|:---:|
-||||
-||||
-||||
-
-
+Initial commit
diff --git a/docker-compose.local.yml b/docker-compose.local.yml
new file mode 100644
index 0000000000000..515481709c086
--- /dev/null
+++ b/docker-compose.local.yml
@@ -0,0 +1,15 @@
+version: '3'
+
+services:
+ gitea:
+ image: gitea/gitea:1.23.0
+ container_name: gitea
+ ports:
+ - "3000:3000"
+ - "222:22"
+ volumes:
+ - ./gitea:/data
+ environment:
+ - USER_UID=1000
+ - USER_GID=1000
+ restart: always
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000000000..5ed0c7a6435f6
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,43 @@
+version: '3.7'
+
+services:
+ gitea:
+ image: gitea/gitea:latest # Gitea Docker image
+ container_name: gitea
+ ports:
+ - "3000:3000" # Expose Gitea web interface on port 3000
+ - "22:22" # Expose SSH port for Git operations
+ environment:
+ - USER_UID=1000
+ - USER_GID=1000
+ - GITEA__database__DB_TYPE=postgres
+ - GITEA__database__HOST=db:5432 # PostgreSQL database service
+ - GITEA__database__NAME=gitea
+ - GITEA__database__USER=gitea_user
+ - GITEA__database__PASSWD=gitea_pass
+ - GITEA__server__DOMAIN=localhost:3000
+ - GITEA__server__SSH_PORT=22
+ depends_on:
+ - db
+ - redis
+ volumes:
+ - ./data:/data # Persistent storage for Gitea data
+
+ db:
+ image: postgres:alpine # PostgreSQL Docker image
+ container_name: db
+ environment:
+ - POSTGRES_DB=gitea
+ - POSTGRES_USER=gitea_user
+ - POSTGRES_PASSWORD=gitea_pass
+ volumes:
+ - ./db-data:/var/lib/postgresql/data # Persistent storage for database
+
+ redis:
+ image: redis:alpine # Redis Docker image
+ container_name: redis
+
+ ports:
+ - "6379:6379" # Expose Redis default port
+ volumes:
+ - ./redis-data:/data # Persistent storage for Redis
diff --git a/main/pom.xml b/main/pom.xml
new file mode 100644
index 0000000000000..bfa4f5321b3e8
--- /dev/null
+++ b/main/pom.xml
@@ -0,0 +1,72 @@
+
+
+
+ 4.0.0
+
+ org.example
+ main
+ 1.0-SNAPSHOT
+
+
+ 21
+ 21
+ UTF-8
+
+
+
+
+
+ org.seleniumhq.selenium
+ selenium-java
+ 4.27.0
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.10.5
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.10.5
+ test
+
+
+
+
+ io.rest-assured
+ rest-assured
+ 5.4.0
+
+
+ io.rest-assured
+ json-path
+ 5.4.0
+
+
+ io.rest-assured
+ xml-path
+ 5.4.0
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.5.2
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 3.1.0
+
+
+
+
+
diff --git a/main/src/main/java/org/example/DriverFactory.java b/main/src/main/java/org/example/DriverFactory.java
new file mode 100644
index 0000000000000..442e5c5ab5f60
--- /dev/null
+++ b/main/src/main/java/org/example/DriverFactory.java
@@ -0,0 +1,62 @@
+package org.example;
+
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.chrome.ChromeOptions;
+import org.openqa.selenium.firefox.FirefoxDriver;
+import org.openqa.selenium.firefox.FirefoxOptions;
+import org.openqa.selenium.remote.RemoteWebDriver;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Optional;
+
+public class DriverFactory {
+
+ private static final String grid_url = System.getenv("GRID_URL");
+
+ private static final String browser = Optional
+ .ofNullable(System.getenv("BROWSER"))
+ .orElse("chrome");
+
+ public static WebDriver getDriver() {
+ if (grid_url != null) {
+ return getRemoteDriver(browser);
+ } else {
+ return getLocalDriver(browser);
+ }
+ }
+
+ private static WebDriver getRemoteDriver(String browser) {
+ URL hubUrl;
+ try {
+ hubUrl = new URI(grid_url).toURL();
+ } catch (URISyntaxException | MalformedURLException err) {
+ throw new IllegalArgumentException("Invalid grid URL");
+ }
+
+ if (browser.equalsIgnoreCase("chrome")) {
+ ChromeOptions options = new ChromeOptions();
+ options.addArguments("--headless");
+ return new RemoteWebDriver(hubUrl, options);
+ } else if (browser.equalsIgnoreCase("firefox")) {
+ FirefoxOptions options = new FirefoxOptions();
+ options.addArguments("-headless");
+ return new RemoteWebDriver(hubUrl, options);
+ } else {
+ throw new IllegalArgumentException("Unsupported browser: " + browser);
+ }
+ }
+
+ private static WebDriver getLocalDriver(String browser) {
+ if (browser.equalsIgnoreCase("chrome")) {
+ return new ChromeDriver();
+ } else if (browser.equalsIgnoreCase("firefox")) {
+ return new FirefoxDriver();
+ } else {
+ throw new IllegalArgumentException("Unsupported browser: " + browser);
+ }
+ }
+}
diff --git a/main/src/main/java/org/example/HomePageGit.java b/main/src/main/java/org/example/HomePageGit.java
new file mode 100644
index 0000000000000..1ccc77b272a1e
--- /dev/null
+++ b/main/src/main/java/org/example/HomePageGit.java
@@ -0,0 +1,66 @@
+package org.example;
+
+import org.junit.jupiter.api.Assertions;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.PageFactory;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.LoadableComponent;
+import org.openqa.selenium.support.ui.Wait;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.time.Duration;
+import java.util.List;
+
+public class HomePageGit extends LoadableComponent {
+ private WebDriver driver;
+ private List elements;
+ private final String baseURL = "http://localhost:3000/user/login";
+ //String baseURL2="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app/user/login";
+ //String baseURL = System.getenv("URL");
+
+ @Override
+ protected void load() {
+ this.driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
+ driver.get(baseURL + "/");
+ System.out.println(driver.getCurrentUrl());
+
+ }
+
+ // @Override
+ protected void isLoaded() throws Error {
+ Assertions.assertTrue(driver.getTitle().contains("Dashboard"));
+
+ }
+
+ // Constructor
+ public HomePageGit(WebDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(driver, this);
+
+ }
+
+ // Method to initialize the elements list (called after the driver is initialized)
+ public void initializeElements() {
+ elements = driver.findElements(By.cssSelector("img.avatar, #_aria_auto_id_5")); // Adjust selectors accordingly
+ }
+
+ public boolean isLoggedInSuccessfully() {
+ System.out.println(driver.getTitle());
+ return driver.getTitle().contains("maias");
+ }
+
+ // Method to click on the image and then the profile button
+ public ProfilePage goToProfilePage() {
+ WebElement profileImage = driver.findElement(By.xpath("//*[@id=\"navbar\"]/div[2]/div[2]/span/img"));
+ profileImage.click();
+ WebElement profilebtn=driver.findElement(By.xpath("//*[@id=\"_aria_auto_id_5\"]"));
+ profilebtn.click();
+
+ return new ProfilePage(driver);
+ }
+}
+
+
+
diff --git a/main/src/main/java/org/example/LoginGit.java b/main/src/main/java/org/example/LoginGit.java
new file mode 100644
index 0000000000000..796c69ae28e13
--- /dev/null
+++ b/main/src/main/java/org/example/LoginGit.java
@@ -0,0 +1,61 @@
+package org.example;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.support.PageFactory;
+import org.openqa.selenium.support.ui.LoadableComponent;
+
+import java.time.Duration;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+public class LoginGit extends LoadableComponent {
+ private WebDriver driver;
+ private final String baseURL="http://localhost:3000";
+ //String baseURL1="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app";
+ private By userNameFieldBy = By.cssSelector("input[name=\"user_name\"]");
+ public By passwordFieldBy = By.cssSelector("input[name=\"password\"]");
+ private By signinButtonBy = By.cssSelector("button.ui.primary.button.tw-w-full");
+
+ public LoginGit(WebDriver driver) {
+ this.driver = driver;
+ PageFactory.initElements(driver,this);
+
+ }
+ public HomePageGit loginAsValidUser(String userName, String password) {
+
+ driver.findElement(userNameFieldBy).sendKeys(userName);
+ driver.findElement(passwordFieldBy).sendKeys(password);
+ driver.findElement(signinButtonBy).click();
+
+ return new HomePageGit(driver);
+ }
+ public LoginGit loginWithInvalidCredentials(String userName, String password){
+ driver.findElement(userNameFieldBy).clear();
+ driver.findElement(userNameFieldBy).sendKeys(userName);
+ driver.findElement(passwordFieldBy).clear();
+ driver.findElement(passwordFieldBy).sendKeys(password);
+ driver.findElement(signinButtonBy).click();
+ return new LoginGit(driver) ;
+ }
+ public boolean isLoginFailed(){
+
+ return driver.getTitle().contains("Sign In");
+ }
+
+ @Override
+ protected void load() {
+ this.driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
+ driver.get(baseURL+"/user/login");
+ System.out.println(driver.getCurrentUrl());
+
+ }
+
+ @Override
+ protected void isLoaded() throws Error {
+ assertTrue(driver.getTitle().contains("Sign In"));
+
+ }
+}
+
diff --git a/main/src/main/java/org/example/Main.java b/main/src/main/java/org/example/Main.java
new file mode 100644
index 0000000000000..03adefcf12528
--- /dev/null
+++ b/main/src/main/java/org/example/Main.java
@@ -0,0 +1,17 @@
+package org.example;
+
+//TIP To Run code, press or
+// click the icon in the gutter.
+public class Main {
+ public static void main(String[] args) {
+ //TIP Press with your caret at the highlighted text
+ // to see how IntelliJ IDEA suggests fixing it.
+ System.out.printf("Hello and welcome!");
+
+ for (int i = 1; i <= 5; i++) {
+ //TIP Press to start debugging your code. We have set one breakpoint
+ // for you, but you can always add more by pressing .
+ System.out.println("i = " + i);
+ }
+ }
+}
diff --git a/main/src/main/java/org/example/NewProjectPage.java b/main/src/main/java/org/example/NewProjectPage.java
new file mode 100644
index 0000000000000..b537d0ac174cc
--- /dev/null
+++ b/main/src/main/java/org/example/NewProjectPage.java
@@ -0,0 +1,131 @@
+package org.example;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+import org.openqa.selenium.support.PageFactory;
+import org.openqa.selenium.support.ui.LoadableComponent;
+import org.openqa.selenium.support.ui.Wait;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.time.Duration;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+public class NewProjectPage extends LoadableComponent {
+ private WebDriver driver;
+ private final String baseURL="http://localhost:3000/user/login";
+ //private static final String baseURL1="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app/user/login";
+
+ // Locators for New Project Fields
+ private By titleField = By.id("_aria_auto_id_0");
+ private By descriptionField = By.id("_combo_markdown_editor_1");
+ private By templateDropdown = By.id("_aria_auto_id_13");
+ private By cardPreviewsDropdown = By.id("_aria_auto_id_17");
+ private By createProjectButton = By.cssSelector(".ui.primary.button");
+ private By cancelButton = By.cssSelector(".ui.cancel.button");
+
+ // Locators for Description Buttons
+ private By boldButton = By.cssSelector("md-bold.markdown-toolbar-button[aria-label='Add bold text']");
+ private By numberProjects=By.cssSelector("div.ui.small.label");
+
+
+ // Constructor
+ public NewProjectPage(WebDriver driver) {
+ this.driver = driver;
+
+ // This call sets the WebElement fields.
+ PageFactory.initElements(driver, this);
+ }
+
+ // Actions for New Project Fields
+ public void enterTitle(String title) {
+ driver.findElement(titleField).sendKeys(title);
+ }
+
+ public void enterDescription(String description) {
+ Wait wait = new WebDriverWait(driver, Duration.ofSeconds(5), Duration.ofMillis(500));
+ wait.until(driver -> driver.findElement(descriptionField).isDisplayed());
+ driver.findElement(descriptionField).sendKeys(description);
+ }
+
+ public void selectTemplate(String templateName) {
+ Actions actions = new Actions(driver);
+
+ // Click the dropdown
+ WebElement dropdown = driver.findElement(By.xpath("//div[@class='ui selection dropdown']"));
+ actions.moveToElement(dropdown).click().perform();
+
+ // Click the option
+ WebElement option = driver.findElement(By.xpath("//div[@role='option' and text()='" + templateName + "']"));
+ actions.moveToElement(option).click().perform();
+ }
+
+
+ public void selectCardPreview(String cardPreviewOption) {
+
+ Actions actions=new Actions(driver);
+
+ WebElement dropdown= driver.findElement(By.xpath("//div[@class='ui selection dropdown']"));
+ actions.moveToElement(dropdown).click().perform();
+
+ WebElement option=driver.findElement(By.xpath("//div[@role='option' and text()='" + cardPreviewOption + "']"));
+ actions.moveToElement(option).click().perform();
+
+ }
+
+ public void clickCreateProject() {
+ driver.findElement(createProjectButton).click();
+ }
+
+ public void clickCancel() {
+ driver.findElement(cancelButton).click();
+ }
+
+ // Actions for Description Buttons
+ public void clickBoldButton() {
+ driver.findElement(boldButton).click();
+ }
+
+
+
+ // Getter for Description Content
+ public String getDescriptionContent() {
+ WebElement previewElement = driver.findElement(descriptionField);
+ String content = previewElement.getAttribute("value");
+ return content;
+ }
+ public int getNumberOfProjects(){
+ WebElement numberElement = driver.findElement(numberProjects);
+
+
+
+ String numberText = numberElement.getText();
+ int number = Integer.parseInt(numberText);
+ return number;
+
+
+ }
+
+ public boolean isSuccessfulProjectPage(){
+
+
+ return driver.getTitle().equals("Projects - Gitea: Git with a cup of tea");
+
+ }
+
+ @Override
+ protected void load() {
+ this.driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(2));
+ driver.get(baseURL+"/maias/-/projects/new");
+ }
+
+ @Override
+ protected void isLoaded() throws Error {
+
+ assertTrue(driver.getTitle().contains("New Project"));
+
+ }
+}
diff --git a/main/src/main/java/org/example/ProfilePage.java b/main/src/main/java/org/example/ProfilePage.java
new file mode 100644
index 0000000000000..1e31a32286ad9
--- /dev/null
+++ b/main/src/main/java/org/example/ProfilePage.java
@@ -0,0 +1,61 @@
+package org.example;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.PageFactory;
+import org.openqa.selenium.support.ui.LoadableComponent;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.time.Duration;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+public class ProfilePage extends LoadableComponent {
+ private WebDriver driver;
+ private final String baseURL="http://localhost:3000/user/login";
+ //private static final String baseURL1="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app/user/login";
+
+ // Locator for the list of project links
+ private By projectLinksBy = By.cssSelector("div.overflow-menu-items a[href='/maias/-/projects']");
+
+ public ProfilePage(WebDriver driver) {
+ this.driver = driver;
+ // This call sets the WebElement fields.
+ PageFactory.initElements(driver, this);
+
+ }
+
+ // Method to click on the Projects link (choosing from the list)
+ public ProjectPage goToProjectsPage() {
+ WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
+
+ // Wait until at least one project link is visible (lambda function for custom condition)
+ List projectLinks = wait.until(driver -> driver.findElements(projectLinksBy));
+ System.out.println(projectLinks);
+ // Select and click on the first available project link (or you can choose any specific link)
+ if (!projectLinks.isEmpty()) {
+ WebElement SecondProjectLink = projectLinks.get(0); // Choose based on index (0 for the first link)
+ SecondProjectLink.click();
+ }
+
+ // Return a new ProjectPage object
+ return new ProjectPage(driver);
+ }
+
+ @Override
+ protected void load() {
+ this.driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(2));
+ driver.get(baseURL+"/maias");
+
+
+ }
+
+ @Override
+ protected void isLoaded() throws Error {
+ assertTrue(driver.getTitle().contains("maias - Gitea"));
+
+ }
+}
diff --git a/main/src/main/java/org/example/ProjectPage.java b/main/src/main/java/org/example/ProjectPage.java
new file mode 100644
index 0000000000000..a5d52d5bd533e
--- /dev/null
+++ b/main/src/main/java/org/example/ProjectPage.java
@@ -0,0 +1,51 @@
+package org.example;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.PageFactory;
+import org.openqa.selenium.support.ui.LoadableComponent;
+
+import java.time.Duration;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class ProjectPage extends LoadableComponent {
+ private WebDriver driver;
+ private final String baseURL="http://localhost:3000/user/login";
+ //private static final String baseURL1="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app/user/login";
+
+ // CSS selector for the "New Project" button
+ private By newProjectButtonBy = By.linkText("New Project");
+
+ public ProjectPage(WebDriver driver) {
+ this.driver = driver;
+ // This call sets the WebElement fields.
+ PageFactory.initElements(driver, this);
+
+ }
+
+ // Method to click the "New Project" button and go to the New Project page
+ public NewProjectPage goToNewProjectPage() {
+ // Find the "New Project" button
+ WebElement newProjectButton = driver.findElement(newProjectButtonBy);
+
+ // Click the "New Project" button
+ newProjectButton.click();
+
+ // Return a new instance of the NewProjectPage class (you need to create this class)
+ return new NewProjectPage(driver);
+ }
+
+ @Override
+ protected void load() {
+ this.driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(2));
+ driver.get(baseURL+"/maias/-/projects");
+ }
+
+ @Override
+ protected void isLoaded() throws Error {
+ assertTrue(driver.getTitle().contains("Projects"));
+
+ }
+}
diff --git a/main/src/test/java/APITests/APITestGiteaTest.java b/main/src/test/java/APITests/APITestGiteaTest.java
new file mode 100644
index 0000000000000..66a1940330cfd
--- /dev/null
+++ b/main/src/test/java/APITests/APITestGiteaTest.java
@@ -0,0 +1,63 @@
+package APITests;
+
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+import java.net.URL;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.CoreMatchers.equalTo;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class APITestGiteaTest {
+
+ private static final String owner = "maias";
+ private static final String apiToken = "30d8417411cb86e107307f3abaa3639954bdaf12";
+ private static final String projectName = "newRepoAPITest";
+
+ @BeforeAll
+ public static void setup() {
+ String dbUrl = "http://localhost:3000";
+ //String baseURL="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app";
+ RestAssured.baseURI =dbUrl + "/api/v1";
+ //System.out.println(dbUrl);
+ }
+
+ @Test
+ @Order(1)
+ public void testCreateRepo() {
+ given()
+ .log().all()
+ .header("Authorization", "token " + apiToken)
+ .contentType(ContentType.JSON)
+ .body("{ \"name\": \"" + projectName + "\", \"private\": false }")
+ .when()
+ .post("/user/repos")
+ .then()
+ .log().all()
+ .statusCode(201)
+ .body("name", equalTo(projectName))
+ .body("private", equalTo(false));
+
+ }
+
+ @Test
+ @Order(2)
+ public void testDeleteRepo() {
+ given()
+ .log().all()
+ .header("Authorization", "token " + apiToken)
+ .when()
+ .delete("/repos/" + owner + "/" + projectName)
+ .then()
+ .log().all()
+ .statusCode(204);
+ }
+
+
+}
diff --git a/main/src/test/java/UITests/LoginGitTest.java b/main/src/test/java/UITests/LoginGitTest.java
new file mode 100644
index 0000000000000..a9053da815f3f
--- /dev/null
+++ b/main/src/test/java/UITests/LoginGitTest.java
@@ -0,0 +1,81 @@
+package UITests;
+
+import org.example.HomePageGit;
+import org.example.LoginGit;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.TimeoutException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.Wait;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.net.MalformedURLException;
+import java.time.Duration;
+
+import static org.example.DriverFactory.getDriver;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class LoginGitTest {
+ WebDriver driver;
+ private LoginGit login;
+ private final String URL="http://localhost:3000/user/login";
+ //String URL="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app/user/login";
+
+
+ @BeforeEach
+ public void setUp() throws MalformedURLException {
+ driver= getDriver();
+ driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(15));
+ driver.manage().window().maximize();
+ driver.get(URL);
+
+ try{
+ Wait wait=new WebDriverWait(driver, Duration.ofSeconds(5));
+ WebElement visitButton= wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//button[text()='Visit Site']")));
+ visitButton.click();
+ }
+ catch (TimeoutException err){
+ System.out.println("Ngrok warning page was not loaded");
+ }
+ login = new LoginGit(driver).get();
+
+ }
+ @Test
+ public void testInvalidLogin() {
+ LoginGit page = login.loginWithInvalidCredentials("wrong", "wrong");
+ assertTrue(page.isLoginFailed(), "Login should fail with invalid credentials");
+ }
+
+ @Test
+ public void testValidLogin() {
+ HomePageGit home = login.loginAsValidUser("maias", "Maias123");
+ assertTrue(home.isLoggedInSuccessfully(), "Login should be successful with valid credentials");
+ }
+
+ @Test
+ public void testEmptyUsername() {
+ LoginGit page = login.loginWithInvalidCredentials("", "Maias123");
+ assertTrue(page.isLoginFailed(), "Login should fail when the username is empty");
+ }
+
+ @Test
+ public void testEmptyPassword() {
+ LoginGit page = login.loginWithInvalidCredentials("maias", "");
+ assertTrue(page.isLoginFailed(), "Login should fail when the password is empty");
+ }
+
+ @Test
+ public void testEmptyUsernameAndPassword() {
+ LoginGit page = login.loginWithInvalidCredentials("", "");
+ assertTrue(page.isLoginFailed(), "Login should fail when both username and password are empty");
+ }
+ @AfterEach
+ public void tearDown() {
+ driver.quit();
+ }
+
+}
diff --git a/main/src/test/java/UITests/NewProjectPageTest.java b/main/src/test/java/UITests/NewProjectPageTest.java
new file mode 100644
index 0000000000000..c20f35dd6fea4
--- /dev/null
+++ b/main/src/test/java/UITests/NewProjectPageTest.java
@@ -0,0 +1,160 @@
+package UITests;
+
+import org.example.*;
+import org.junit.jupiter.api.*;
+import org.openqa.selenium.By;
+import org.openqa.selenium.TimeoutException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.Wait;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.net.MalformedURLException;
+import java.time.Duration;
+
+import static org.example.DriverFactory.getDriver;
+import static org.junit.jupiter.api.Assertions.*;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class NewProjectPageTest {
+ private WebDriver driver;
+ private ProjectPage projectPage;
+ private LoginGit login;
+ private HomePageGit home;
+ private ProfilePage profile;
+ private NewProjectPage newProjectPage;
+ private final String URL = "http://localhost:3000/user/login";
+ String URL2="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app/user/login";
+
+ @BeforeEach
+ public void setUp() throws MalformedURLException {
+ driver = getDriver();
+ driver.manage().window().maximize();
+ driver.get(URL);
+ try {
+ Wait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
+ WebElement visitButton = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//button[text()='Visit Site']")));
+ visitButton.click();
+ } catch (TimeoutException err) {
+ System.out.println("Ngrok warning page was not loaded");
+ }
+ login = new LoginGit(driver).get();
+ }
+
+ @Test
+ @Order(1)
+ public void testCreateProject() {
+ //the bot pattern
+ newProjectPage = login.loginAsValidUser("maias", "Maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage();
+ newProjectPage.enterTitle("Test1 Project");
+ newProjectPage.enterDescription("This is a test project description.");
+ newProjectPage.selectTemplate("None");
+ newProjectPage.selectCardPreview("Images and Text");
+ newProjectPage.clickCreateProject();
+ assertTrue(newProjectPage.isSuccessfulProjectPage());
+ }
+ @Test
+ @Order(2)//if we have emty title the project will not create
+ public void testEmptyFields() {
+ //the bot pattern
+ newProjectPage=login.loginAsValidUser("maias", "Maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage();
+ newProjectPage.enterTitle("");
+ newProjectPage.enterDescription("this is Description");
+ newProjectPage.clickCreateProject();
+ assertFalse(newProjectPage.isSuccessfulProjectPage());
+
+
+ }
+ @Test
+ @Order(3)
+ //if we have emty title the project will not create
+ public void testTitleOnly() {
+ //the bot pattern
+ newProjectPage=login.loginAsValidUser("maias", "Maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage();
+ newProjectPage.enterTitle("Test 3 Project2");
+ newProjectPage.clickCreateProject();
+ assertTrue(newProjectPage.isSuccessfulProjectPage());
+
+
+ }
+ /* @Test //if we have emty title the project will not create
+ public void testCancelButton() {
+ newProjectPage=login.loginAsValidUser("maias", "maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage();
+ newProjectPage.enterTitle("Test 4 Project");
+ newProjectPage.enterDescription("This is a test project description.");
+ newProjectPage.selectTemplate("None");
+ newProjectPage.selectCardPreview("Images and Text");
+ int numberProjectBefore= newProjectPage.getNumberOfProjects();
+ newProjectPage.clickCancel();
+ int numberProjectafter=newProjectPage.getNumberOfProjects();
+ assertEquals(numberProjectBefore,numberProjectafter);
+
+
+ }
+
+ @Test// test BoldStyle after we write the description
+ public void testBoldStyleInDescription() {
+ newProjectPage=login.loginAsValidUser("maias", "maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage();
+ newProjectPage.enterTitle("Test5 Project");
+ newProjectPage.enterDescription("This is a test description.");
+ newProjectPage.selectTemplate("Basic Kanban");
+ newProjectPage.selectCardPreview("Text Only");
+ // Apply bold styling
+ newProjectPage.clickBoldButton();
+ // Get the HTML content after applying bold
+ String afterBoldHtml = newProjectPage.getDescriptionContent();
+ // Verify that bold tags are added in the HTML
+ assertTrue(afterBoldHtml.contains("****") ,
+ "Bold styling was not applied in the description preview.");
+ //Verify the content inside the bold tags is as expected
+ assertTrue(afterBoldHtml.contains("This is a test description."),
+ "Description content is incorrect after applying bold styling.");
+ // Create the project
+ newProjectPage.clickCreateProject();
+ // Verify that the project was created successfully
+ assertTrue(newProjectPage.isSuccessfulProjectPage());
+ }
+ @Test// test BoldStyle before we write the description
+ public void testBoldStyleInDescription2() {
+ newProjectPage=login.loginAsValidUser("maias", "maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage();
+ newProjectPage.enterTitle("Test6 Project");
+ newProjectPage.clickBoldButton();
+ newProjectPage.enterDescription("This is a test description.");
+ newProjectPage.selectTemplate("Basic Kanban");
+ newProjectPage.selectCardPreview("Text Only");
+ // Get the HTML content after applying bold
+ String afterBoldHtml = newProjectPage.getDescriptionContent();
+ // Verify that bold tags are added in the HTML
+ assertTrue(afterBoldHtml.equals("**This is a test description.**") ,
+ "Bold styling was not applied in the description preview.");
+ //Verify the content inside the bold tags is as expected
+ assertTrue(afterBoldHtml.contains("This is a test description."),
+ "Description content is incorrect after applying bold styling.");
+ // Create the project
+ newProjectPage.clickCreateProject();
+ // Verify that the project was created successfully
+ assertTrue(newProjectPage.isSuccessfulProjectPage());
+ }
+ @Test// test BoldStyle for some words we write the description
+ public void testBoldStyleInDescription3() {
+ newProjectPage=login.loginAsValidUser("maias", "maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage();
+ newProjectPage.enterTitle("Test 7 Project");
+ newProjectPage.enterDescription("This is a test description.");
+ newProjectPage.clickBoldButton();
+ newProjectPage.enterDescription("maias ");
+ newProjectPage.selectTemplate("Basic Kanban");
+ newProjectPage.selectCardPreview("Text Only");
+ newProjectPage.enterDescription("This not Bold");
+ String afterAdditionalText=newProjectPage.getDescriptionContent();
+ assertTrue(afterAdditionalText.equals("This is a test description.**maias **This not Bold"),"Bold styling was not applied in the description preview.");
+ newProjectPage.clickCreateProject();
+ assertTrue(newProjectPage.isSuccessfulProjectPage());
+ }*/
+ @AfterEach
+ public void tearDown() {
+ driver.quit();
+ }
+
+}
+
diff --git a/main/target/classes/org/example/DriverFactory.class b/main/target/classes/org/example/DriverFactory.class
new file mode 100644
index 0000000000000..d6f1dd2c519b1
Binary files /dev/null and b/main/target/classes/org/example/DriverFactory.class differ
diff --git a/main/target/classes/org/example/HomePageGit.class b/main/target/classes/org/example/HomePageGit.class
new file mode 100644
index 0000000000000..bf74e9c03ab5a
Binary files /dev/null and b/main/target/classes/org/example/HomePageGit.class differ
diff --git a/main/target/classes/org/example/LoginGit.class b/main/target/classes/org/example/LoginGit.class
new file mode 100644
index 0000000000000..8d65a046b0f80
Binary files /dev/null and b/main/target/classes/org/example/LoginGit.class differ
diff --git a/main/target/classes/org/example/Main.class b/main/target/classes/org/example/Main.class
new file mode 100644
index 0000000000000..4426061088818
Binary files /dev/null and b/main/target/classes/org/example/Main.class differ
diff --git a/main/target/classes/org/example/NewProjectPage.class b/main/target/classes/org/example/NewProjectPage.class
new file mode 100644
index 0000000000000..0cbfc091cc81b
Binary files /dev/null and b/main/target/classes/org/example/NewProjectPage.class differ
diff --git a/main/target/classes/org/example/ProfilePage.class b/main/target/classes/org/example/ProfilePage.class
new file mode 100644
index 0000000000000..2a421a31c6be2
Binary files /dev/null and b/main/target/classes/org/example/ProfilePage.class differ
diff --git a/main/target/classes/org/example/ProjectPage.class b/main/target/classes/org/example/ProjectPage.class
new file mode 100644
index 0000000000000..78e6b877ad19d
Binary files /dev/null and b/main/target/classes/org/example/ProjectPage.class differ
diff --git a/main/target/test-classes/APITests/APITestGiteaTest.class b/main/target/test-classes/APITests/APITestGiteaTest.class
new file mode 100644
index 0000000000000..a8789a6390de4
Binary files /dev/null and b/main/target/test-classes/APITests/APITestGiteaTest.class differ
diff --git a/main/target/test-classes/UITests/LoginGitTest.class b/main/target/test-classes/UITests/LoginGitTest.class
new file mode 100644
index 0000000000000..2d236a7e52c74
Binary files /dev/null and b/main/target/test-classes/UITests/LoginGitTest.class differ
diff --git a/main/target/test-classes/UITests/NewProjectPageTest.class b/main/target/test-classes/UITests/NewProjectPageTest.class
new file mode 100644
index 0000000000000..935e370265f00
Binary files /dev/null and b/main/target/test-classes/UITests/NewProjectPageTest.class differ
diff --git a/newfile.txt b/newfile.txt
new file mode 100644
index 0000000000000..e69de29bb2d1d