Skip to content

Commit

Permalink
Review fix and improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Timshel committed Feb 21, 2024
1 parent 20a4688 commit e77b4c4
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 169 deletions.
1 change: 1 addition & 0 deletions test/scenarios/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ node_modules/
/test-results/
/playwright-report/
/playwright/.cache/
temp
27 changes: 27 additions & 0 deletions test/scenarios/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ It usse its own [test.env](/test/scenarios/test.env) with different ports to not

```bash
npm install
npx playwright install firefox
```

## Usage
Expand All @@ -24,6 +25,32 @@ To access the ui to easily run test individually and debug if needed:
npx playwright test --ui
```

### DB

Projects are configured to allow to run tests only on specific database.
\
You can use:

```bash
npx playwright test --project sqllite
npx playwright test --project postgres
npx playwright test --project mysql
```

### Running specific tests

To run a whole file you can :

```bash
npx playwright test --project sqllite tests/login.spec.ts
```

To run only a specifc test (It might fail if it has dependency):

```bash
npx playwright test --project sqllite -g "Account creation"
```

## Writing scenario

When creating new scenario use the recorder to more easily identify elements (in general try to rely on visible hint to identify elements and not hidden ids).
Expand Down
16 changes: 6 additions & 10 deletions test/scenarios/global-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import yaml from 'js-yaml';
const utils = require('./global-utils');

utils.loadEnv();
var kcPath = process.env.KC_SETUP_PATH;

function readCurrentVersion(){
try {
const vw_version_file = fs.readFileSync('data/web-vault/vw-version.json', {
const vw_version_file = fs.readFileSync('temp/web-vault/vw-version.json', {
encoding: 'utf8',
flag: 'r'
});
Expand Down Expand Up @@ -46,12 +45,9 @@ function retrieveFrontend(){

try {
if( vv != `v${vw_version}`) {
fs.rmSync("./data/web-vault", { recursive: true, force: true });
fs.rmSync("./temp/web-vault", { recursive: true, force: true });

execSync(`cd data && wget -c https://github.com/dani-garcia/bw_web_builds/releases/download/${vv}/bw_web_${vv}.tar.gz -O - | tar xz`, { stdio: "inherit" });

// Make the SSO button visible
execSync(`bash -c "sed -i 's#a.routerlink=./sso..,##' data/web-vault/app/main.*.css"`, { stdio: "inherit" });
execSync(`cd temp && wget -c https://github.com/dani-garcia/bw_web_builds/releases/download/${vv}/bw_web_${vv}.tar.gz -O - | tar xz`, { stdio: "inherit" });

console.log(`Retrieved bw_web_builds-${vv}`);
} else {
Expand All @@ -64,17 +60,17 @@ function retrieveFrontend(){
}

function buildServer(){
if( !fs.existsSync('data/vaultwarden') ){
if( !fs.existsSync('temp/vaultwarden') ){
console.log("Rebuilding server");
execSync(`cd ../.. && cargo build --features sqlite,mysql,postgresql --release`, { stdio: "inherit" });
execSync(`cp ../../target/release/vaultwarden data/vaultwarden`, { stdio: "inherit" });
execSync(`cp ../../target/release/vaultwarden temp/vaultwarden`, { stdio: "inherit" });
} else {
console.log("Using existing server");
}
}

async function globalSetup(config: FullConfig) {
execSync("mkdir -p data/logs");
execSync("mkdir -p temp/logs");

buildServer();
retrieveFrontend();
Expand Down
108 changes: 91 additions & 17 deletions test/scenarios/global-utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type Browser } from '@playwright/test';
import { type Browser, type TestInfo } from '@playwright/test';
import { execSync } from 'node:child_process';
import dotenv from 'dotenv';
import dotenvExpand from 'dotenv-expand';

Expand Down Expand Up @@ -31,35 +32,108 @@ async function waitFor(url: String, browser: Browser) {
} while(!ready);
}

async function startVaultWarden(browser: Browser, env = {}, reset: Boolean = true) {
if( reset ){
fs.rmSync("data/db.sqlite3", { force: true });
fs.rmSync("data/db.sqlite3-shm", { force: true });
fs.rmSync("data/db.sqlite3-wal", { force: true });
function startStopSqlite(){
fs.rmSync("temp/db.sqlite3", { force: true });
fs.rmSync("temp/db.sqlite3-shm", { force: true });
fs.rmSync("temp/db.sqlite3-wal", { force: true });
}

function startMariaDB() {
console.log(`Starting MariaDB`);
execSync(`docker run --rm --name ${process.env.MARIADB_CONTAINER} \
-e MARIADB_ROOT_PASSWORD=${process.env.MARIADB_PWD} \
-e MARIADB_USER=${process.env.MARIADB_USER} \
-e MARIADB_PASSWORD=${process.env.MARIADB_PWD} \
-e MARIADB_DATABASE=${process.env.MARIADB_DB} \
-p ${process.env.MARIADB_PORT}:3306 \
-d mariadb:10.4`
);
}


function stopMariaDB() {
console.log("Stopping MariaDB (ensure DB is wiped)");
execSync(`docker stop ${process.env.MARIADB_CONTAINER} || true`);
}

function startPostgres() {
console.log(`Starting Postgres`);
execSync(`docker run --rm --name ${process.env.POSTGRES_CONTAINER} \
-e POSTGRES_USER=${process.env.POSTGRES_USER} \
-e POSTGRES_PASSWORD=${process.env.POSTGRES_PWD} \
-e POSTGRES_DB=${process.env.POSTGRES_DB} \
-p ${process.env.POSTGRES_PORT}:5432 \
-d postgres:16.2`
);
};

function stopPostgres() {
console.log("Stopping Postgres (Ensure DB is wiped)");
execSync(`docker stop ${process.env.POSTGRES_CONTAINER} || true`);
}

function dbConfig(testInfo: TestInfo){
switch(testInfo.project.name) {
case "postgres": return {
DATABASE_URL: `postgresql://${process.env.POSTGRES_USER}:${process.env.POSTGRES_PWD}@127.0.0.1:${process.env.POSTGRES_PORT}/${process.env.POSTGRES_DB}`
}
case "mysql": return {
DATABASE_URL: `mysql://${process.env.MARIADB_USER}:${process.env.MARIADB_PWD}@127.0.0.1:${process.env.MARIADB_PORT}/${process.env.MARIADB_DB}`
}
default: return { I_REALLY_WANT_VOLATILE_STORAGE: true }
}
}

async function startVaultwarden(browser: Browser, testInfo: TestInfo, env = {}, resetDB: Boolean = true) {
if( resetDB ){
switch(testInfo.project.name) {
case "postgres":
stopPostgres();
startPostgres()
break;
case "mysql":
stopMariaDB();
startMariaDB();
break;
default:
startStopSqlite();
}
}

const vw_log = fs.openSync("data/logs/vaultwarden.log", "a");
var proc = spawn("../../target/release/vaultwarden", {
env: { ...process.env, ...env },
const vw_log = fs.openSync("temp/logs/vaultwarden.log", "a");
var proc = spawn("temp/vaultwarden", {
env: { ...process.env, ...env, ...dbConfig(testInfo) },
stdio: [process.stdin, vw_log, vw_log]
});

await waitFor("/", browser);

console.log(`VaultWarden running on: ${process.env.DOMAIN}`);
console.log(`Vaultwarden running on: ${process.env.DOMAIN}`);

return proc;
}

async function stopVaultWarden(proc) {
console.log(`VaultWarden stopping`);
async function stopVaultwarden(proc, testInfo: TestInfo, resetDB: Boolean = true) {
console.log(`Vaultwarden stopping`);
proc.kill();
}

async function restartVaultWarden(proc, browser: Browser, env) {
stopVaultWarden(proc);
return startVaultWarden(browser, env, false);
if( resetDB ){
switch(testInfo.project.name) {
case "postgres":
stopPostgres();
break;
case "mysql":
stopMariaDB();
break;
default:
startStopSqlite();
}
}
}

async function restartVaultwarden(proc, browser: Browser, testInfo: TestInfo, env, resetDB: Boolean = true) {
stopVaultwarden(proc, testInfo, resetDB);
return startVaultwarden(browser, testInfo, env, resetDB);
}

export { loadEnv, waitFor, startVaultWarden, stopVaultWarden, restartVaultWarden };
export { loadEnv, waitFor, startVaultwarden, stopVaultwarden, restartVaultwarden };
10 changes: 9 additions & 1 deletion test/scenarios/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,15 @@ export default defineConfig({
/* Configure projects for major browsers */
projects: [
{
name: 'firefox',
name: 'sqllite',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'postgres',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'mysql',
use: { ...devices['Desktop Firefox'] },
},
],
Expand Down
19 changes: 5 additions & 14 deletions test/scenarios/test.env
Original file line number Diff line number Diff line change
@@ -1,31 +1,22 @@
##################################################################
### Shared Playwright conf test file VaultWarden and Databases ###
### Shared Playwright conf test file Vaultwarden and Databases ###
##################################################################

#############
# Test user #
#############
TEST_USER=test
TEST_USER_PASSWORD=${TEST_USER}
TEST_USER_MAIL="${TEST_USER}@yopmail.com"
TEST_USER_MAIL="${TEST_USER}@example.com"

######################
# VaultWarden Exec #
# Vaultwarden Config #
######################
DATA_FOLDER=temp
WEB_VAULT_FOLDER=temp/web-vault/

######################
# VaultWarden Config #
######################
ROCKET_PORT=8001
DOMAIN=http://127.0.0.1:${ROCKET_PORT}
I_REALLY_WANT_VOLATILE_STORAGE=true
SSO_ENABLED=true
SSO_ONLY=false
SSO_CLIENT_ID=VaultWarden
SSO_CLIENT_SECRET=VaultWarden
SSO_AUTHORITY=http://${KC_HTTP_HOST}:${KC_HTTP_PORT}/realms/${TEST_REALM}

WEB_VAULT_FOLDER=data/web-vault/

###########################
# Docker MariaDb container#
Expand Down
43 changes: 0 additions & 43 deletions test/scenarios/tests/login-common.ts

This file was deleted.

53 changes: 43 additions & 10 deletions test/scenarios/tests/login.spec.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,54 @@
import { test, expect } from '@playwright/test';
import { test, expect, type TestInfo } from '@playwright/test';
const utils = require('../global-utils');
const { create_account, login } = require('./login-common');

utils.loadEnv();

var proc;

test.beforeAll('Setup', async ({ browser }) => {
proc = await utils.startVaultWarden(browser, {
SSO_ENABLED: false
});
test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => {
proc = await utils.startVaultwarden(browser, testInfo, {});
});

test.afterAll('Teardown', async () => {
utils.stopVaultWarden(proc);
test.afterAll('Teardown', async ({}, testInfo: TestInfo) => {
utils.stopVaultwarden(proc, testInfo);
});

test('Account creation', create_account);
test('Account creation', async ({ page }) => {
// Landing page
await page.goto('/');
await page.getByRole('link', { name: 'Create account' }).click();

test('Master password login', login);
// Back to Vault create account
await expect(page).toHaveTitle(/Create account | Vaultwarden Web/);
await page.getByLabel(/Email address/).fill(process.env.TEST_USER_MAIL);
await page.getByLabel('Name').fill(process.env.TEST_USER);
await page.getByLabel('Master password\n (required)', { exact: true }).fill('Master password');
await page.getByLabel('Re-type master password').fill('Master password');
await page.getByRole('button', { name: 'Create account' }).click();

// Back to the login page
await expect(page).toHaveTitle('Vaultwarden Web');
await page.getByLabel('Your new account has been created')
await page.getByRole('button', { name: 'Continue' }).click();

// Unlock page
await page.getByLabel('Master password').fill('Master password');
await page.getByRole('button', { name: 'Log in with master password' }).click();

// We are now in the default vault page
await expect(page).toHaveTitle(/Vaults/);
});

test('Master password login', async ({ page }) => {
// Landing page
await page.goto('/');
await page.getByLabel(/Email address/).fill(process.env.TEST_USER_MAIL);
await page.getByRole('button', { name: 'Continue' }).click();

// Unlock page
await page.getByLabel('Master password').fill('Master password');
await page.getByRole('button', { name: 'Log in with master password' }).click();

// We are now in the default vault page
await expect(page).toHaveTitle(/Vaults/);
});
Loading

0 comments on commit e77b4c4

Please sign in to comment.