From a31ecca41aa6933e91e271f12453c6ee8586dee9 Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Sat, 3 Jun 2023 17:21:28 +0200 Subject: [PATCH] tests(e2e): refactor register user to insert directly in db --- .github/workflows/e2e.yml | 15 +++++ e2e/0002-login.spec.ts | 7 +- e2e/0003-apps.spec.ts | 15 +++-- e2e/fixtures/fixtures.ts | 23 +++---- e2e/helpers/db.ts | 28 ++++---- package.json | 1 - playwright.config.ts | 22 +++---- scripts/start-prod.sh | 74 ---------------------- src/client/components/ui/Header/Header.tsx | 2 +- 9 files changed, 62 insertions(+), 125 deletions(-) delete mode 100755 scripts/start-prod.sh diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index e49ad26d..785ec9ee 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -197,6 +197,21 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | + const comments = await github.rest.issues.listComments({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo + }); + + const comment = comments.data.find(comment => comment.body.includes('Playwright report:')); + + if (comment) { + await github.rest.issues.deleteComment({ + comment_id: comment.id, + owner: context.repo.owner, + repo: context.repo.repo + }); + } github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, diff --git a/e2e/0002-login.spec.ts b/e2e/0002-login.spec.ts index 8ba5cb86..19f86eb4 100644 --- a/e2e/0002-login.spec.ts +++ b/e2e/0002-login.spec.ts @@ -1,14 +1,14 @@ import { test, expect } from '@playwright/test'; -import { registerUser } from './fixtures/fixtures'; +import { loginUser, createTestUser } from './fixtures/fixtures'; import { testUser } from './helpers/constants'; import { clearDatabase } from './helpers/db'; -test.beforeEach(async ({ page }) => { +test.beforeEach(async () => { await clearDatabase(); - await registerUser(page); }); test('user can login and is redirected to the dashboard', async ({ page }) => { + await createTestUser(); await page.goto('/login'); await page.getByPlaceholder('you@example.com').fill(testUser.email); @@ -19,6 +19,7 @@ test('user can login and is redirected to the dashboard', async ({ page }) => { }); test('user can logout', async ({ page }) => { + await loginUser(page); await page.getByTestId('logout-button').click(); await expect(page.getByText('Login to your account')).toBeVisible(); diff --git a/e2e/0003-apps.spec.ts b/e2e/0003-apps.spec.ts index 9bf2fe3e..82faa43a 100644 --- a/e2e/0003-apps.spec.ts +++ b/e2e/0003-apps.spec.ts @@ -1,16 +1,19 @@ import { test, expect } from '@playwright/test'; -import { registerUser } from './fixtures/fixtures'; +import { loginUser } from './fixtures/fixtures'; import { clearDatabase } from './helpers/db'; test.beforeEach(async ({ page, isMobile }) => { await clearDatabase(); - await registerUser(page); + await loginUser(page); - // Go to hello world app if (isMobile) { - await page.getByTestId('navbar-menu').click(); + // TODO: Fix mobile accessibility for the dropdown menu + // await page.getByRole('button', { name: 'Menu' }).click(); + await page.goto('/app-store'); + } else { + await page.getByRole('link', { name: 'App store' }).click(); } - await page.getByRole('link', { name: 'App store' }).click(); + await page.getByPlaceholder('Search').fill('hello'); await page.getByRole('link', { name: 'Hello World' }).click(); }); @@ -27,7 +30,7 @@ test('user can install and uninstall app', async ({ page, context }) => { await expect(page.getByText('Running')).toBeVisible({ timeout: 60000 }); await expect(page.getByText('App installed successfully')).toBeVisible(); - const [newPage] = await Promise.all([context.waitForEvent('page'), page.getByRole('button', { name: 'Open' }).click()]); + const [newPage] = await Promise.all([context.waitForEvent('page'), await page.getByTestId('app-details').getByRole('button', { name: 'Open' }).click()]); await newPage.waitForLoadState(); await expect(newPage.getByText('Hello World')).toBeVisible(); diff --git a/e2e/fixtures/fixtures.ts b/e2e/fixtures/fixtures.ts index 412e6403..4966483f 100644 --- a/e2e/fixtures/fixtures.ts +++ b/e2e/fixtures/fixtures.ts @@ -1,24 +1,25 @@ +import * as argon2 from 'argon2'; import { expect, Page } from '@playwright/test'; +import { userTable } from '@/server/db/schema'; +import { db } from '../helpers/db'; import { testUser } from '../helpers/constants'; -export const registerUser = async (page: Page) => { - await page.goto('/register'); - await page.getByPlaceholder('you@example.com').click(); - await page.getByPlaceholder('you@example.com').fill(testUser.email); - - await page.getByPlaceholder('Enter your password', { exact: true }).fill(testUser.password); - await page.getByPlaceholder('Confirm your password').fill(testUser.password); - - await page.getByRole('button', { name: 'Register' }).click(); - await expect(page).toHaveTitle(/Dashboard/); +export const createTestUser = async () => { + // Create user in database + const password = await argon2.hash(testUser.password); + await db.insert(userTable).values({ password, username: testUser.email, operator: true }); }; export const loginUser = async (page: Page) => { + // Create user in database + await createTestUser(); + + // Login flow await page.goto('/login'); await page.getByPlaceholder('you@example.com').fill(testUser.email); await page.getByPlaceholder('Your password').fill(testUser.password); await page.getByRole('button', { name: 'Login' }).click(); - await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeDefined(); + await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible(); }; diff --git a/e2e/helpers/db.ts b/e2e/helpers/db.ts index 553552ad..868927f2 100644 --- a/e2e/helpers/db.ts +++ b/e2e/helpers/db.ts @@ -1,19 +1,17 @@ -import pg from 'pg'; +import { Pool } from 'pg'; +import { drizzle } from 'drizzle-orm/node-postgres'; +import * as schema from '../../src/server/db/schema'; + +const connectionString = `postgresql://tipi:postgres@${process.env.SERVER_IP}:5432/tipi?connect_timeout=300`; + +const pool = new Pool({ + connectionString, +}); + +export const db = drizzle(pool, { schema }); export const clearDatabase = async () => { - const pgClient = new pg.Client({ - user: 'tipi', - host: process.env.SERVER_IP, - database: 'tipi', - password: 'postgres', - port: 5432, - }); - - await pgClient.connect(); - // delete all data in table user - await pgClient.query('DELETE FROM "user"'); - await pgClient.query('DELETE FROM "app"'); - - await pgClient.end(); + await db.delete(schema.userTable); + await db.delete(schema.appTable); }; diff --git a/package.json b/package.json index 02be0416..5360ad3c 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ "start:dev-container": "./.devcontainer/filewatcher.sh && npm run start:dev", "start:rc": "docker-compose -f docker-compose.rc.yml --env-file .env up --build", "start:dev": "./scripts/start-dev.sh", - "start:prod": "./scripts/start-prod.sh", "start:e2e": "./scripts/start-e2e.sh latest", "start:pg": "docker run --name test-db -p 5433:5432 -d --rm -e POSTGRES_PASSWORD=postgres postgres:14", "version": "echo $npm_package_version", diff --git a/playwright.config.ts b/playwright.config.ts index 8d035809..69559b69 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,11 +1,5 @@ import { defineConfig, devices } from '@playwright/test'; -/** - * Read environment variables from file. - * https://github.com/motdotla/dotenv - */ -// require('dotenv').config(); - /** * See https://playwright.dev/docs/test-configuration. */ @@ -42,15 +36,15 @@ export default defineConfig({ use: { ...devices['Desktop Chrome'] }, }, - { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, - }, + // { + // name: 'firefox', + // use: { ...devices['Desktop Firefox'] }, + // }, - { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - }, + // { + // name: 'webkit', + // use: { ...devices['Desktop Safari'] }, + // }, /* Test against mobile viewports. */ { diff --git a/scripts/start-prod.sh b/scripts/start-prod.sh deleted file mode 100755 index 5e785b37..00000000 --- a/scripts/start-prod.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bash -set -o errexit -set -o nounset -set -o pipefail -if [[ "${TRACE-0}" == "1" ]]; then - set -o xtrace -fi - -source "${BASH_SOURCE%/*}/common.sh" - -clean_logs - -### -------------------------------- -### General variables -### -------------------------------- -ROOT_FOLDER="${PWD}" -STATE_FOLDER="${ROOT_FOLDER}/state" - -### -------------------------------- -### Apps repository configuration -### -------------------------------- -apps_repository="https://github.com/meienberger/runtipi-appstore" - -env_variables_json=$(cat <"${ROOT_FOLDER}/state/system-info.json" -fi - -chmod -R a+rwx "${ROOT_FOLDER}/state/events" -chmod -R a+rwx "${ROOT_FOLDER}/state/system-info.json" -kill_watcher -"${ROOT_FOLDER}/scripts/watcher.sh" & - -### -------------------------------- -### env file generation -### -------------------------------- -generate_env_file "${env_variables_json}" - -### -------------------------------- -### Start the project -### -------------------------------- -docker compose -f docker-compose.test.yml up --build diff --git a/src/client/components/ui/Header/Header.tsx b/src/client/components/ui/Header/Header.tsx index 7703ece5..79e51b9b 100644 --- a/src/client/components/ui/Header/Header.tsx +++ b/src/client/components/ui/Header/Header.tsx @@ -30,7 +30,7 @@ export const Header: React.FC = ({ isUpdateAvailable }) => { return (
-