diff --git a/.env b/.env index f0e23e465..d9aee909c 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ -SPRINT=sprint5 \ No newline at end of file +SPRINT_FOLDER=sprint5-with-bugs + diff --git a/.github/workflows/api-test.yml b/.github/workflows/api-test.yml new file mode 100644 index 000000000..e77cc3d6f --- /dev/null +++ b/.github/workflows/api-test.yml @@ -0,0 +1,32 @@ +name: Run API Tests with Newman + +on: + push: + branches: [ "main" ] + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install Newman + run: npm install -g newman + + - name: Run API tests with Newman + run: | + newman run users.postman_collection.json -d data.json --reporters cli,html --reporter-html-export report.html + + - name: Upload HTML report + uses: actions/upload-artifact@v3 + with: + name: newman-report + path: report.html diff --git a/README.md b/README.md index 0ca511796..702cf5464 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ [![Run Playwright Tests 🎭](https://github.com/testsmith-io/practice-software-testing/actions/workflows/run-tests.yml/badge.svg)](https://github.com/testsmith-io/practice-software-testing/actions/workflows/run-tests.yml) [![StackShare](http://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](https://stackshare.io/testsmith-io/practice-software-testing) +docker-compose exec laravel-api php artisan migrate:fresh --seed + + + # Default accounts | First name | Last name | Role | E-mail | Password | diff --git a/_docker/ui.docker b/_docker/ui.docker index 3a03f3f47..bca3b316b 100644 --- a/_docker/ui.docker +++ b/_docker/ui.docker @@ -1,28 +1,7 @@ -# Stage 1: Base image -FROM node:20.19-alpine as base +FROM node:22.12.0-alpine RUN apk update && \ apk add bash && \ - npm install -g npm@10.9.2 + npm install -g npm@10.2.4 -RUN npm install -g @angular/cli@latest - -WORKDIR /app - -# Stage 2: Development (no code copy) -FROM base as development -EXPOSE 4200 -CMD ["ng", "serve", "--host", "0.0.0.0", "--port", "4200"] - -# Stage 3: Production (with code copy) -FROM base as production - -# Copy package files and install dependencies -COPY package*.json ./ -RUN npm install --legacy-peer-deps --force - -# Copy application code -COPY . ./ - -EXPOSE 4200 -CMD ["ng", "serve", "--host", "0.0.0.0", "--port", "4200"] +RUN npm install -s -g @angular/cli@latest diff --git a/data.json b/data.json new file mode 100644 index 000000000..e3f57286e --- /dev/null +++ b/data.json @@ -0,0 +1,17 @@ +[ + { + "email": "invaliduser@example.com", + "password": "wrongpassword", + "searchTerm": "invalid" + }, + { + "email": "customer@practicesoftwaretesting.com", + "password": "welcome01", + "searchTerm": "john" + }, + { + "email": "", + "password": "", + "searchTerm": "" + } +] diff --git a/docker-compose.yml b/docker-compose.yml index 5b9030628..16d0ea0ba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,7 +23,9 @@ services: target: development working_dir: /app volumes: - - ./${SPRINT}/UI:/app:cached + - ./${SPRINT_FOLDER}/UI:/app:cached + - /app/node_modules + ports: - 4200:4200 command: > @@ -54,7 +56,7 @@ services: mariadb: image: yobasystems/alpine-mariadb:10.6.11 ports: - - 3306:3306 + - 3307:3306 expose: - 3306 environment: diff --git a/users.postman_collection.json b/users.postman_collection.json new file mode 100644 index 000000000..dc00fa0b6 --- /dev/null +++ b/users.postman_collection.json @@ -0,0 +1,198 @@ +{ + "info": { + "name": "User API Collection", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Register User", + "request": { + "method": "POST", + "header": [{ "key": "Content-Type", "value": "application/json" }], + "body": { + "mode": "raw", + "raw": "{\n \"email\": \"{{email}}\",\n \"password\": \"{{password}}\"\n}" + }, + "url": { + "raw": "{{base_url}}/users/register", + "host": ["{{base_url}}"], + "path": ["users", "register"] + } + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "if (pm.response.code === 201) {", + " pm.test(\"Register - Success\", function () {", + " pm.response.to.have.status(201);", + " });", + "} else {", + " pm.test(\"Register - Failed\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([400, 401, 403]);", + " });", + "}" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Login User", + "request": { + "method": "POST", + "header": [{ "key": "Content-Type", "value": "application/json" }], + "body": { + "mode": "raw", + "raw": "{\n \"email\": \"{{email}}\",\n \"password\": \"{{password}}\"\n}" + }, + "url": { + "raw": "{{base_url}}/users/login", + "host": ["{{base_url}}"], + "path": ["users", "login"] + } + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "if (pm.response.code === 200) {", + " var json = pm.response.json();", + " pm.test(\"Login - Success\", function () {", + " pm.expect(json).to.have.property(\"access_token\");", + " pm.environment.set(\"authToken\", json.access_token);", + " pm.expect(json).to.have.status(200);", + " });", + "} else {", + " pm.test(\"Login - Failed\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([400, 401]);", + " });", + "}" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Get User Info", + "request": { + "method": "GET", + "header": [{ "key": "Authorization", "value": "Bearer {{authToken}}" }], + "url": { + "raw": "{{base_url}}/users/me", + "host": ["{{base_url}}"], + "path": ["users", "me"] + } + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "if (pm.response.code === 200) {", + " var json = pm.response.json();", + " pm.test(\"Get User Info - Success\", function () {", + " pm.response.to.have.status(200);", + " });", + "} else {", + " pm.test(\"Get User Info - Failed\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([400, 401]);", + " });", + "}" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Logout User", + "request": { + "method": "GET", + "header": [{ "key": "Authorization", "value": "Bearer {{authToken}}" }], + "url": { + "raw": "{{base_url}}/users/logout", + "host": ["{{base_url}}"], + "path": ["users", "logout"] + } + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "if (pm.response.code === 200) {", + " var json = pm.response.json();", + " pm.test(\"Logout - Success\", function () {", + " pm.expect(json).to.have.property(\"message\");", + " pm.expect(json).to.have.status(200);", + " });", + "} else {", + " pm.test(\"Logout - Failed\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([400, 401]);", + " });", + "}" + ], + "type": "text/javascript" + } + } + ] + }, + { + "name": "Search User", + "request": { + "method": "GET", + "header": [{ "key": "Authorization", "value": "Bearer {{authToken}}" }], + "url": { + "raw": "{{base_url}}/users/search?term={{searchTerm}}", + "host": ["{{base_url}}"], + "path": ["users", "search"], + "query": [{ "key": "term", "value": "{{searchTerm}}" }] + } + }, + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Search User - Status OK/Unauthorized/NotFound\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 401, 404]);", + "});", + "", + "if (pm.response.code === 200) {", + " let jsonData = pm.response.json();", + " ", + " pm.test(\"Search User - Response is an array\", function () {", + " pm.expect(Array.isArray(jsonData)).to.be.true;", + " });", + "", + " if (jsonData.length > 0) {", + " const user = jsonData[0];", + " pm.test(\"Search User - User object contains expected fields\", function () {", + " pm.expect(user).to.have.property(\"first_name\");", + " pm.expect(user).to.have.property(\"last_name\");", + " pm.expect(user).to.have.property(\"city\");", + " pm.expect(user).to.have.property(\"email\");", + " pm.expect(user).to.have.property(\"id\");", + " });", + " }", + "}" + ], + "type": "text/javascript" + } + } + ] + } + ], + "event": [], + "variable": [ + { + "key": "base_url", + "value": "https://api-with-bugs.practicesoftwaretesting.com" + } + ] +}