From 2e7c39eea1bdfe3d8b4c64015cdd1bca1f105841 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 8 Aug 2024 23:03:11 +0100 Subject: [PATCH 01/22] [aws] chore: Deploy to aws --- .github/workflows/backend-deploy-aws.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/workflows/backend-deploy-aws.yml diff --git a/.github/workflows/backend-deploy-aws.yml b/.github/workflows/backend-deploy-aws.yml new file mode 100644 index 00000000..ea13dea4 --- /dev/null +++ b/.github/workflows/backend-deploy-aws.yml @@ -0,0 +1,16 @@ +name: Deploy Backend to AWS + +on: + push: + branches: [aws-deploy] + +jobs: + deploy: + runs-on: ec2-runner-be + steps: + - name: Pull image from docker hub + run: docker pull push ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest + - name: Delete old container + run: docker rm -f notes-app-be + - name: Run docker container + run: docker run -e DATABASE_URL=${{ secrets.PROD_DATABASE_URL }} -e JWT_SECRET=${{ secrets.JWT_SECRET }} -d -p 5000:5000 --name notes-app-be push ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest \ No newline at end of file From 32a81ffd66395b6e12f69d1a6705c4ff258023b1 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 8 Aug 2024 23:13:32 +0100 Subject: [PATCH 02/22] [aws] chore: Deploy to aws --- .github/workflows/backend-deploy-aws.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backend-deploy-aws.yml b/.github/workflows/backend-deploy-aws.yml index ea13dea4..443241ed 100644 --- a/.github/workflows/backend-deploy-aws.yml +++ b/.github/workflows/backend-deploy-aws.yml @@ -9,7 +9,7 @@ jobs: runs-on: ec2-runner-be steps: - name: Pull image from docker hub - run: docker pull push ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest + run: docker pull ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest - name: Delete old container run: docker rm -f notes-app-be - name: Run docker container From 272e1e2e58e4215d63adc8e6c04c21556ffac512 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 8 Aug 2024 23:14:54 +0100 Subject: [PATCH 03/22] [aws] chore: Deploy to aws --- .github/workflows/backend-deploy-aws.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/backend-deploy-aws.yml b/.github/workflows/backend-deploy-aws.yml index 443241ed..aba913a5 100644 --- a/.github/workflows/backend-deploy-aws.yml +++ b/.github/workflows/backend-deploy-aws.yml @@ -8,6 +8,8 @@ jobs: deploy: runs-on: ec2-runner-be steps: + - name: Login to docker hub + run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} - name: Pull image from docker hub run: docker pull ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest - name: Delete old container From 085bdf16a27a2af0ee09fbb9224d7b55e4b15251 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 8 Aug 2024 23:25:08 +0100 Subject: [PATCH 04/22] [aws] chore: Deploy to aws --- .github/workflows/backend-deploy-aws.yml | 2 -- .github/workflows/backend-docker-push.yml | 10 ++-------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/backend-deploy-aws.yml b/.github/workflows/backend-deploy-aws.yml index aba913a5..443241ed 100644 --- a/.github/workflows/backend-deploy-aws.yml +++ b/.github/workflows/backend-deploy-aws.yml @@ -8,8 +8,6 @@ jobs: deploy: runs-on: ec2-runner-be steps: - - name: Login to docker hub - run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} - name: Pull image from docker hub run: docker pull ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest - name: Delete old container diff --git a/.github/workflows/backend-docker-push.yml b/.github/workflows/backend-docker-push.yml index 3cd9525f..080fbe7d 100644 --- a/.github/workflows/backend-docker-push.yml +++ b/.github/workflows/backend-docker-push.yml @@ -25,15 +25,9 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Extract version from tag - id: extract_version - run: echo "::set-output name=VERSION::$(echo ${GITHUB_REF/refs\/tags\//} | cut -d'/' -f2)" - name: Build and push Docker image - env: - IMAGE_TAG: ${{ steps.extract_version.outputs.VERSION }} run: | yarn docker:app:build - docker tag notes-app-be:latest ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:$IMAGE_TAG - docker push ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:$IMAGE_TAG + docker tag notes-app-be:latest ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest + docker push ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest From 8de63292e31bf90cbd7c12983046709188a3c827 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 8 Aug 2024 23:26:05 +0100 Subject: [PATCH 05/22] [aws] chore: Deploy to aws --- .github/workflows/backend-docker-push.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/backend-docker-push.yml b/.github/workflows/backend-docker-push.yml index 080fbe7d..ad7f7f29 100644 --- a/.github/workflows/backend-docker-push.yml +++ b/.github/workflows/backend-docker-push.yml @@ -2,8 +2,7 @@ name: Docker Push Backend on: push: - tags: - - "be/*.*" + branches: [aws-deploy] defaults: run: working-directory: ./backend From 7c326ffbadde8b241d36af7f55b3faaed64d59ba Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 8 Aug 2024 23:36:26 +0100 Subject: [PATCH 06/22] [aws] chore: Deploy to aws --- .github/workflows/backend-deploy-aws.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backend-deploy-aws.yml b/.github/workflows/backend-deploy-aws.yml index 443241ed..2ce54b80 100644 --- a/.github/workflows/backend-deploy-aws.yml +++ b/.github/workflows/backend-deploy-aws.yml @@ -13,4 +13,4 @@ jobs: - name: Delete old container run: docker rm -f notes-app-be - name: Run docker container - run: docker run -e DATABASE_URL=${{ secrets.PROD_DATABASE_URL }} -e JWT_SECRET=${{ secrets.JWT_SECRET }} -d -p 5000:5000 --name notes-app-be push ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest \ No newline at end of file + run: docker run -e DATABASE_URL=${{ secrets.PROD_DATABASE_URL }} -e JWT_SECRET=${{ secrets.JWT_SECRET }} -d -p 5000:5000 --name notes-app-be ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest \ No newline at end of file From 776657bb7051f198d354daa2447672739d1d79d3 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Sat, 10 Aug 2024 20:53:34 +0100 Subject: [PATCH 07/22] [aws] chore: Deploy to aws --- .github/workflows/frontend-deploy-aws.yml | 16 ++++++++++++++++ .github/workflows/frontend-docker-push.yml | 19 ++++++------------- 2 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/frontend-deploy-aws.yml diff --git a/.github/workflows/frontend-deploy-aws.yml b/.github/workflows/frontend-deploy-aws.yml new file mode 100644 index 00000000..e2893254 --- /dev/null +++ b/.github/workflows/frontend-deploy-aws.yml @@ -0,0 +1,16 @@ +name: Deploy Frontend to AWS + +on: + push: + branches: [aws-deploy] + +jobs: + deploy: + runs-on: ec2-runner-fe + steps: + - name: Pull image from docker hub + run: docker pull ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest + - name: Delete old container + run: docker rm -f notes-app-fe + - name: Run docker container + run: docker run -e REACT_APP_API_BASE_URL=${{ secrets.PROD_API_URL }} -d -p 3000:3000 --name notes-app-fe ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest \ No newline at end of file diff --git a/.github/workflows/frontend-docker-push.yml b/.github/workflows/frontend-docker-push.yml index a7b916e1..d401d708 100644 --- a/.github/workflows/frontend-docker-push.yml +++ b/.github/workflows/frontend-docker-push.yml @@ -2,8 +2,7 @@ name: Docker Push Frontend on: push: - tags: - - "fe/*.*" # Trigger on any tag creation + branches: [aws-deploy] defaults: run: working-directory: ./frontend @@ -18,22 +17,16 @@ jobs: - uses: actions/checkout@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Extract version from tag - id: extract_version - run: echo "::set-output name=VERSION::$(echo ${GITHUB_REF/refs\/tags\//} | cut -d'/' -f2)" - name: Build and push Docker image - env: - IMAGE_TAG: ${{ steps.extract_version.outputs.VERSION }} run: | - yarn docker:build - docker tag notes-app-fe:latest ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:$IMAGE_TAG - docker push ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:$IMAGE_TAG + yarn docker:app:build + docker tag notes-app-fe:latest ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest + docker push ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest From 51aafd3881a49ace34fad980f4ff5d2b1ade2751 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Sat, 10 Aug 2024 20:56:31 +0100 Subject: [PATCH 08/22] [aws] chore: Deploy to aws --- .github/workflows/frontend-docker-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/frontend-docker-push.yml b/.github/workflows/frontend-docker-push.yml index d401d708..7f8cf8fc 100644 --- a/.github/workflows/frontend-docker-push.yml +++ b/.github/workflows/frontend-docker-push.yml @@ -27,6 +27,6 @@ jobs: - name: Build and push Docker image run: | - yarn docker:app:build + yarn docker:build docker tag notes-app-fe:latest ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest docker push ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest From ba68e6b624ff33723d28c55e76aaa8b1f058d74b Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Sat, 10 Aug 2024 21:12:10 +0100 Subject: [PATCH 09/22] [aws] chore: Deploy to aws --- .github/workflows/frontend-deploy-aws.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/frontend-deploy-aws.yml b/.github/workflows/frontend-deploy-aws.yml index e2893254..6985c36a 100644 --- a/.github/workflows/frontend-deploy-aws.yml +++ b/.github/workflows/frontend-deploy-aws.yml @@ -13,4 +13,4 @@ jobs: - name: Delete old container run: docker rm -f notes-app-fe - name: Run docker container - run: docker run -e REACT_APP_API_BASE_URL=${{ secrets.PROD_API_URL }} -d -p 3000:3000 --name notes-app-fe ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest \ No newline at end of file + run: docker run -e REACT_APP_API_BASE_URL=${{ secrets.REACT_APP_API_BASE_URL }} -d -p 3000:3000 --name notes-app-fe ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest \ No newline at end of file From 175e32b10bc4dde7bc4d717aece39b8f6d0bf874 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Sat, 10 Aug 2024 21:17:56 +0100 Subject: [PATCH 10/22] [aws] chore: Deploy to aws --- .github/workflows/frontend-docker-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/frontend-docker-push.yml b/.github/workflows/frontend-docker-push.yml index 7f8cf8fc..56d7be7e 100644 --- a/.github/workflows/frontend-docker-push.yml +++ b/.github/workflows/frontend-docker-push.yml @@ -27,6 +27,6 @@ jobs: - name: Build and push Docker image run: | - yarn docker:build + docker build --build-arg REACT_APP_API_BASE_URL=${{ secrets.REACT_APP_API_BASE_URL }} -t notes-app-fe . docker tag notes-app-fe:latest ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest docker push ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest From ad49dc8d5dca92d72132bfebcef86dc2337bfc22 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Sat, 10 Aug 2024 21:23:14 +0100 Subject: [PATCH 11/22] [aws] chore: Deploy to aws --- .github/workflows/backend-deploy-aws.yml | 6 ++++-- .github/workflows/frontend-deploy-aws.yml | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/backend-deploy-aws.yml b/.github/workflows/backend-deploy-aws.yml index 2ce54b80..e85de3a6 100644 --- a/.github/workflows/backend-deploy-aws.yml +++ b/.github/workflows/backend-deploy-aws.yml @@ -8,9 +8,11 @@ jobs: deploy: runs-on: ec2-runner-be steps: - - name: Pull image from docker hub - run: docker pull ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest - name: Delete old container run: docker rm -f notes-app-be + - name: Prune docker system + run: docker system prune -f + - name: Pull image from docker hub + run: docker pull ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest - name: Run docker container run: docker run -e DATABASE_URL=${{ secrets.PROD_DATABASE_URL }} -e JWT_SECRET=${{ secrets.JWT_SECRET }} -d -p 5000:5000 --name notes-app-be ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-be:latest \ No newline at end of file diff --git a/.github/workflows/frontend-deploy-aws.yml b/.github/workflows/frontend-deploy-aws.yml index 6985c36a..d958bda0 100644 --- a/.github/workflows/frontend-deploy-aws.yml +++ b/.github/workflows/frontend-deploy-aws.yml @@ -8,9 +8,11 @@ jobs: deploy: runs-on: ec2-runner-fe steps: - - name: Pull image from docker hub - run: docker pull ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest - name: Delete old container run: docker rm -f notes-app-fe + - name: Prune docker system + run: docker system prune -f + - name: Pull image from docker hub + run: docker pull ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest - name: Run docker container run: docker run -e REACT_APP_API_BASE_URL=${{ secrets.REACT_APP_API_BASE_URL }} -d -p 3000:3000 --name notes-app-fe ${{ secrets.DOCKERHUB_USERNAME }}/notes-app-fe:latest \ No newline at end of file From 5203ffbce3ad46fc86035eca26e21216db66dec8 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Sat, 17 Aug 2024 14:07:44 +0100 Subject: [PATCH 12/22] [aws] chore: Deploy to aws --- .github/workflows/backend-deploy-aws.yml | 2 +- .github/workflows/frontend-deploy-aws.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backend-deploy-aws.yml b/.github/workflows/backend-deploy-aws.yml index e85de3a6..fb1d5bd5 100644 --- a/.github/workflows/backend-deploy-aws.yml +++ b/.github/workflows/backend-deploy-aws.yml @@ -8,7 +8,7 @@ jobs: deploy: runs-on: ec2-runner-be steps: - - name: Delete old container + - name: Delete old be container run: docker rm -f notes-app-be - name: Prune docker system run: docker system prune -f diff --git a/.github/workflows/frontend-deploy-aws.yml b/.github/workflows/frontend-deploy-aws.yml index d958bda0..d37fb377 100644 --- a/.github/workflows/frontend-deploy-aws.yml +++ b/.github/workflows/frontend-deploy-aws.yml @@ -8,7 +8,7 @@ jobs: deploy: runs-on: ec2-runner-fe steps: - - name: Delete old container + - name: Delete old fe container run: docker rm -f notes-app-fe - name: Prune docker system run: docker system prune -f From 156777fbd4f3ea391b8a5fef452e1a0674e40109 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Sat, 17 Aug 2024 23:35:16 +0100 Subject: [PATCH 13/22] [aws] chore: Deploy to aws --- backend/src/index.ts | 2 +- backend/tests/integration/notes.spec.ts | 4 ++-- frontend/src/components/Note.tsx | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/backend/src/index.ts b/backend/src/index.ts index aeb55d64..10c438a3 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -23,7 +23,7 @@ app.use('/', noteRoutes); app.use('/', userRoutes); app.use('/', loginRoutes); -app.get('/health', (req, res) => { +app.get('/api/health', (req, res) => { res.json({ status: 'ok' }); }); diff --git a/backend/tests/integration/notes.spec.ts b/backend/tests/integration/notes.spec.ts index 37ad95aa..83c75ad7 100644 --- a/backend/tests/integration/notes.spec.ts +++ b/backend/tests/integration/notes.spec.ts @@ -223,8 +223,8 @@ describe('Delete a note', () => { }); describe('Health check', () => { - test('GET /health', async ({}) => { - const response = await request(app).get('/health'); + test('GET /api/health', async ({}) => { + const response = await request(app).get('/api/health'); expect(response.status).toBe(200); expect(response.body).toStrictEqual({ status: 'ok' }); }); diff --git a/frontend/src/components/Note.tsx b/frontend/src/components/Note.tsx index dab00e9a..b3b4299f 100644 --- a/frontend/src/components/Note.tsx +++ b/frontend/src/components/Note.tsx @@ -1,4 +1,5 @@ import type NoteType from '../types/note'; +import dayjs from 'dayjs'; interface NoteProps { note: NoteType; @@ -24,7 +25,7 @@ const Note: React.FC = ({ note, handleEdit, deleteNote }) => {

- Updated {new Date(note.updatedAt ?? '').toLocaleDateString()} + Updated: {dayjs(note.updatedAt).format('DD MMM YY')}

+
); }; diff --git a/frontend/src/api/apiService.ts b/frontend/src/api/apiService.ts index 2e053caf..24f5bc91 100644 --- a/frontend/src/api/apiService.ts +++ b/frontend/src/api/apiService.ts @@ -77,6 +77,11 @@ export const login = async (username: string, password: string) => { return response; }; +export const getUser = async () => { + const response = await api.get('user'); + return response; +}; + export const createUser = async (user: { username: string; email: string; diff --git a/frontend/src/components/UserModal.test.tsx b/frontend/src/components/UserModal.test.tsx new file mode 100644 index 00000000..4d0971d0 --- /dev/null +++ b/frontend/src/components/UserModal.test.tsx @@ -0,0 +1,43 @@ +import { render, screen } from '@testing-library/react'; +import UserModal from './UserModal'; + +describe('UserModal', () => { + test('should see User Information when present', () => { + render( + {}} + user={{ + username: 'Test User', + email: 'helloitsme@email.com', + createdAt: '2023-02-05T23:34:42.260Z', + updatedAt: '2024-02-05T20:11:42.260Z', + }} + />, + ); + // Assert that the form elements are rendered correctly + expect(screen.getByText('User Information')).toBeInTheDocument(); + + expect(screen.getByText('Username:')).toBeInTheDocument(); + expect(screen.getByText('Test User')).toBeInTheDocument(); + + expect(screen.getByText('Email:')).toBeInTheDocument(); + expect(screen.getByText('helloitsme@email.com')).toBeInTheDocument(); + + expect(screen.getByText('Created:')).toBeInTheDocument(); + expect(screen.getByText('05 Feb 2023 23:34')).toBeInTheDocument(); + + expect(screen.getByText('Last updated:')).toBeInTheDocument(); + expect(screen.getByText('05 Feb 2024 20:11')).toBeInTheDocument(); + }); + test('should see error message when user information is not present', () => { + render( + {}} user={null} />, + ); + + expect(screen.getByText('User Information')).toBeInTheDocument(); + expect( + screen.getByText('Error: No user information available'), + ).toBeInTheDocument(); + }); +}); diff --git a/frontend/src/components/UserModal.tsx b/frontend/src/components/UserModal.tsx new file mode 100644 index 00000000..d927550f --- /dev/null +++ b/frontend/src/components/UserModal.tsx @@ -0,0 +1,47 @@ +import { Modal } from 'antd'; +import dayjs from 'dayjs'; +import UserType from '../types/user'; + +interface UserModalProps { + isModalVisible: boolean; + handleCancel: () => void; + user: UserType | null; +} + +const dateFormat = 'DD MMM YYYY HH:mm'; + +const UserModal: React.FC = (props) => { + return ( + + {props.user ? ( +
+

+ Username: {props.user?.username} +

+

+ Email: {props.user?.email} +

+

+ Created:{' '} + {dayjs(props.user?.createdAt).format(dateFormat)} +

+

+ Last updated:{' '} + {dayjs(props.user?.updatedAt).format(dateFormat)} +

+
+ ) : ( +

+ Error: No user information available +

+ )} +
+ ); +}; + +export default UserModal; diff --git a/frontend/src/types/user.tsx b/frontend/src/types/user.tsx new file mode 100644 index 00000000..495b8ad4 --- /dev/null +++ b/frontend/src/types/user.tsx @@ -0,0 +1,8 @@ +type UserType = { + username: string; + email: string; + createdAt?: string; + updatedAt?: string; +}; + +export default UserType; diff --git a/playwright/pages/NotesPage.ts b/playwright/pages/NotesPage.ts index fef9aaca..6cdf91b7 100644 --- a/playwright/pages/NotesPage.ts +++ b/playwright/pages/NotesPage.ts @@ -1,15 +1,19 @@ import { Page } from '@playwright/test'; +import UserProfileModal from './UserProfileModal'; class NotesPage { private page: Page; + private userProfileModal: UserProfileModal; constructor(page: Page) { this.page = page; + this.userProfileModal = new UserProfileModal(page); } spinnerContainer = () => this.page.getByTestId('spinner-container'); addNewNoteButton = () => this.page.getByRole('button', { name: 'Add a Note' }); + profileButton = () => this.page.getByRole('button', { name: 'Profile' }); addNoteTitleInput = () => this.page.getByPlaceholder('Title'); addNoteContentInput = () => this.page.getByPlaceholder('Content'); addNoteButton = () => this.page.getByRole('button', { name: 'Add Note' }); @@ -21,6 +25,12 @@ class NotesPage { closeNoteModalButton = () => this.page.locator('[class*="modal-close"]').first(); + async viewUserProfile() { + await this.profileButton().click(); + await this.userProfileModal.modal().waitFor({ state: 'visible' }); + return this.userProfileModal; + } + async goto() { await this.page.goto('/'); await this.page.waitForLoadState('domcontentloaded'); diff --git a/playwright/pages/UserProfileModal.ts b/playwright/pages/UserProfileModal.ts new file mode 100644 index 00000000..66ef1901 --- /dev/null +++ b/playwright/pages/UserProfileModal.ts @@ -0,0 +1,19 @@ +import { Page } from '@playwright/test'; + +class UserProfileModal { + private page: Page; + + constructor(page: Page) { + this.page = page; + } + + modal = () => this.page.getByTestId('user-info-modal'); + username = () => this.page.getByTestId('user-info-username'); + email = () => this.page.getByTestId('user-info-email'); + + async close() { + await this.page.locator('[class*="modal-close"]').first().click(); + } +} + +export default UserProfileModal; diff --git a/playwright/tests/user.profile.spec.ts b/playwright/tests/user.profile.spec.ts new file mode 100644 index 00000000..27bbd342 --- /dev/null +++ b/playwright/tests/user.profile.spec.ts @@ -0,0 +1,40 @@ +/* eslint-disable prettier/prettier */ +import { test, expect, Page } from '@playwright/test'; +import { allure } from 'allure-playwright'; +import LoginPage from '../pages/LoginPage'; +import NotesPage from '../pages/NotesPage'; + +let page: Page; +let loginPage: LoginPage; +let notesPage: NotesPage; + +const timeout = 2 * 60 * 1000; + +test.beforeAll(async ({ browser }) => { + await allure.feature('User Profile'); + page = await browser.newPage(); + loginPage = new LoginPage(page); + notesPage = new NotesPage(page); +}); + +test.beforeEach(async () => { + await loginPage.goto(); + await loginPage.login('dave', 'test'); + await expect(page).toHaveTitle(/Notes/, { timeout }); + await expect(notesPage.spinnerContainer()).toBeHidden({ timeout }); +}); + +test.describe('Notes App User Info', { tag: ['@PRODUCTION'] }, async () => { + test('should be able to view user profile information', async () => { + const profilePageModal = await notesPage.viewUserProfile(); + + await expect(profilePageModal.modal()).toBeVisible(); + await expect(profilePageModal.username()).toContainText('dave'); + await expect(profilePageModal.email()).toContainText('@'); + + + await profilePageModal.close(); + await expect(profilePageModal.modal()).toBeHidden(); + }); + +}); From 753a9b02d75467dcd48b2abccd3bac6f69781eeb Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Sun, 18 Aug 2024 20:26:10 +0100 Subject: [PATCH 17/22] [aws] feat: User Profile --- backend/tests/e2e/users.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/tests/e2e/users.spec.ts b/backend/tests/e2e/users.spec.ts index c11026ba..c777ad74 100644 --- a/backend/tests/e2e/users.spec.ts +++ b/backend/tests/e2e/users.spec.ts @@ -42,7 +42,7 @@ describe('Authenticated Flows', () => { expect(getUsersResponse.body.length).toBeGreaterThan(0); }); - test.only('Get the user response', async () => { + test('Get the user response', async () => { const getUsersResponse = await request(USER_URL) .get('/') .set('Authorization', `Bearer ${token}`); From a0a5b0e4c2cd67e5af345c2e819b7e14c16eb961 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Sun, 18 Aug 2024 20:29:19 +0100 Subject: [PATCH 18/22] [aws] feat: User Profile --- backend/tests/integration/users.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/tests/integration/users.spec.ts b/backend/tests/integration/users.spec.ts index b81352d1..1f24be0a 100644 --- a/backend/tests/integration/users.spec.ts +++ b/backend/tests/integration/users.spec.ts @@ -56,7 +56,7 @@ describe('Get Users', () => { }); }); -describe.only('Get user', () => { +describe('Get user', () => { test('GET user info for existing user', async () => { prisma.user.findFirst.mockResolvedValue({ id: 'ccf89a7e-b941-4f17-bbe0-4e0c8b2cd272', From 6910e76acb1fc5116eb7745f44870e91a147c468 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Sun, 18 Aug 2024 20:48:27 +0100 Subject: [PATCH 19/22] [aws] feat: User Profile --- .github/workflows/backend-deploy-aws.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/backend-deploy-aws.yml b/.github/workflows/backend-deploy-aws.yml index 3a277989..c24b6210 100644 --- a/.github/workflows/backend-deploy-aws.yml +++ b/.github/workflows/backend-deploy-aws.yml @@ -35,6 +35,8 @@ jobs: steps: - name: Delete old be container run: docker rm -f notes-app-be + - name: Delete old be image + run: docker image rm -f ${{ secrets.DOCKERHUB_USERNAME }}notes-app-fe - name: Prune docker system run: docker system prune -f - name: Pull image from docker hub From 0faeedcc6fc6314a1b7857ae6fb35c9ef65dac00 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Sun, 18 Aug 2024 21:40:57 +0100 Subject: [PATCH 20/22] [aws] feat: User Profile --- backend/Dockerfile | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 215ab822..aceb3311 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,37 +1,36 @@ # Use an official Node.js runtime based on Alpine Linux as the base image -FROM node:20-alpine - -# Install bash -RUN apk add --no-cache bash +FROM node:20-alpine as builder # Set the working directory inside the container WORKDIR /usr/src/app -# Copy package.json and package-lock.json to the working directory -COPY package.json yarn.lock ./ +# Install dependencies required for the build +RUN apk add --no-cache bash openssl3 + +# Copy package.json, package-lock.json, and TypeScript configuration files +COPY package.json yarn.lock tsconfig.json ./ # Install the application dependencies RUN yarn -# Required for prisma -RUN apk add openssl3 - -# Copy the TypeScript configuration files -COPY tsconfig.json ./ - -# Copy the application code into the container -COPY . . - +# Copy the application code and other necessary files into the container +COPY . ./ COPY wait-for-it.sh wait-for-it.sh -# Make the script executable -RUN chmod +x wait-for-it.sh +# Make the script executable and build the application +RUN chmod +x wait-for-it.sh && \ + npx prisma generate && \ + yarn build + +# Use a new, clean base image for the runtime +FROM node:20-alpine -# Primsa generate -RUN npx prisma generate +WORKDIR /usr/src/app -# Build TypeScript code -RUN yarn build +# Copy only the built artifacts and necessary files from the builder stage +COPY --from=builder /usr/src/app/dist ./dist +COPY --from=builder /usr/src/app/node_modules ./node_modules +COPY --from=builder /usr/src/app/wait-for-it.sh ./wait-for-it.sh # Expose the port that the application will run on EXPOSE 5000 From 3f03002b40f03d4f4ea993f282307de793136b23 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Sun, 18 Aug 2024 22:17:38 +0100 Subject: [PATCH 21/22] [aws] feat: User Profile --- backend/Dockerfile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index aceb3311..6b0e390f 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -27,10 +27,14 @@ FROM node:20-alpine WORKDIR /usr/src/app +# Install dependencies required for the build +RUN apk add --no-cache bash + # Copy only the built artifacts and necessary files from the builder stage -COPY --from=builder /usr/src/app/dist ./dist -COPY --from=builder /usr/src/app/node_modules ./node_modules -COPY --from=builder /usr/src/app/wait-for-it.sh ./wait-for-it.sh +COPY --from=builder /usr/src/app/ ./ + +# Copy the wait-for-it.sh script and make it executable +RUN chmod +x wait-for-it.sh # Expose the port that the application will run on EXPOSE 5000 From e53de3e3aca780038a33b2e33ad500c75232d3dd Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Mon, 19 Aug 2024 10:58:38 +0100 Subject: [PATCH 22/22] [aws] feat: User Profile --- .github/workflows/backend-deploy-aws.yml | 5 +- .github/workflows/backend-deploy.yml | 14 ---- .github/workflows/frontend-deploy-aws.yml | 3 +- .github/workflows/frontend-deploy.yml | 14 ---- .../frontend-service-tests-deploy.yml | 70 ------------------- 5 files changed, 3 insertions(+), 103 deletions(-) delete mode 100644 .github/workflows/backend-deploy.yml delete mode 100644 .github/workflows/frontend-deploy.yml delete mode 100644 .github/workflows/frontend-service-tests-deploy.yml diff --git a/.github/workflows/backend-deploy-aws.yml b/.github/workflows/backend-deploy-aws.yml index c24b6210..4c66aa87 100644 --- a/.github/workflows/backend-deploy-aws.yml +++ b/.github/workflows/backend-deploy-aws.yml @@ -1,9 +1,8 @@ name: Deploy Backend to AWS on: - push: - branches: [aws-deploy] - + workflow_dispatch: + jobs: build: defaults: diff --git a/.github/workflows/backend-deploy.yml b/.github/workflows/backend-deploy.yml deleted file mode 100644 index e9368820..00000000 --- a/.github/workflows/backend-deploy.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Backend Production Deploy - -on: - workflow_dispatch: - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Deploy to production - uses: johnbeynon/render-deploy-action@v0.0.8 - with: - service-id: ${{ secrets.MY_RENDER_SERVICE_ID_BE }} - api-key: ${{ secrets.MY_RENDER_API_KEY }} diff --git a/.github/workflows/frontend-deploy-aws.yml b/.github/workflows/frontend-deploy-aws.yml index 445d5e40..1ee86907 100644 --- a/.github/workflows/frontend-deploy-aws.yml +++ b/.github/workflows/frontend-deploy-aws.yml @@ -1,8 +1,7 @@ name: Deploy Frontend to AWS on: - push: - branches: [aws-deploy] + workflow_dispatch: permissions: write-all diff --git a/.github/workflows/frontend-deploy.yml b/.github/workflows/frontend-deploy.yml deleted file mode 100644 index 1a658699..00000000 --- a/.github/workflows/frontend-deploy.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Frontend Production Deploy - -on: - workflow_dispatch: - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Deploy to production - uses: johnbeynon/render-deploy-action@v0.0.8 - with: - service-id: ${{ secrets.MY_RENDER_SERVICE_ID_FE }} - api-key: ${{ secrets.MY_RENDER_API_KEY }} diff --git a/.github/workflows/frontend-service-tests-deploy.yml b/.github/workflows/frontend-service-tests-deploy.yml deleted file mode 100644 index 71fd69b7..00000000 --- a/.github/workflows/frontend-service-tests-deploy.yml +++ /dev/null @@ -1,70 +0,0 @@ -name: Frontend Service Tests - Deploy to Production - -on: - push: - branches: [ "main" ] - paths: - - "frontend/**" - -jobs: - build: - runs-on: ubuntu-latest - env: - API_URL: http://localhost:5000 - steps: - - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Use Node.js 20.x - uses: actions/setup-node@v4 - with: - node-version: 20.x - - - name: Create .env file - run: | - cd ./backend - echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" > .env - - - name: Start service in docker - run: | - cd ./backend - yarn docker:up - - - name: Wait for service to start - run: | - sleep 15 - - - name: Test connectivity - run: curl ${API_URL} - - - name: Install and start frontend - run: | - cd ./frontend - yarn - yarn build - yarn start & - - - name: Install Playwright - run: | - cd ./playwright - yarn - yarn playwright install chromium - - - name: Run Playwright Tests against chromium - run: | - cd ./playwright - yarn test:chromium - - - name: Stop service in docker - run: | - cd ./backend - yarn docker:down - - - name: Deploy FE to production - uses: johnbeynon/render-deploy-action@v0.0.8 - - with: - service-id: ${{ secrets.MY_RENDER_SERVICE_ID_FE }} - api-key: ${{ secrets.MY_RENDER_API_KEY }}