tests(e2e): refactor register user to insert directly in db

This commit is contained in:
Nicolas Meienberger 2023-06-03 17:21:28 +02:00 committed by Nicolas Meienberger
parent 6b6aba9545
commit a31ecca41a
9 changed files with 62 additions and 125 deletions

View file

@ -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,

View file

@ -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();

View file

@ -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();

View file

@ -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();
};

View file

@ -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);
};

View file

@ -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",

View file

@ -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. */
{

View file

@ -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 <<EOF
{
"dns_ip": "9.9.9.9",
"domain": "tipi.localhost",
"root_folder": "${ROOT_FOLDER}",
"nginx_port": 3000,
"nginx_port_ssl": 443,
"jwt_secret": "secret",
"postgres_password": "postgres",
"postgres_username": "tipi",
"postgres_dbname": "tipi",
"postgres_port": 5432,
"postgres_host": "tipi-db",
"redis_host": "tipi-redis",
"tipi_version": "$(get_json_field "${ROOT_FOLDER}/package.json" version)",
"internal_ip": "localhost",
"demo_mode": false,
"apps_repository": "${apps_repository}",
"storage_path": "${ROOT_FOLDER}",
"repo_id": "$("${ROOT_FOLDER}"/scripts/git.sh get_hash ${apps_repository})"
}
EOF
)
### --------------------------------
### Watcher and system-info
### --------------------------------
mkdir -p "${ROOT_FOLDER}/state"
if [[ ! -f "${ROOT_FOLDER}/state/events" ]]; then
touch "${ROOT_FOLDER}/state/events"
fi
if [[ ! -f "${ROOT_FOLDER}/state/system-info.json" ]]; then
echo "{}" >"${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

View file

@ -30,7 +30,7 @@ export const Header: React.FC<IProps> = ({ isUpdateAvailable }) => {
return (
<header className="text-white navbar navbar-expand-md navbar-dark navbar-overlap d-print-none" data-bs-theme="dark">
<div className="container-xl">
<button data-testid="navbar-menu" aria-label="menu" className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar-menu">
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar-menu">
<span className="navbar-toggler-icon" />
</button>
<Link href="/" passHref>