(e2e) add specific accounts for testing

This creates a bunch of accounts with various profiles
to allow testing in a specific "mode"
This commit is contained in:
Quentin BEY
2024-11-13 16:54:54 +01:00
committed by BEY Quentin
parent 6123e11dd4
commit 59f3499799
13 changed files with 394 additions and 48 deletions

View File

@@ -99,6 +99,216 @@
}
],
"realmRoles": ["user"]
},
{
"username": "jean.team-member",
"email": "jean.team-member@example.com",
"firstName": "E2E",
"lastName": "Group Member",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.team-member"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.team-administrator",
"email": "jean.team-administrator@example.com",
"firstName": "E2E",
"lastName": "Group Administrator",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.team-administrator"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.team-owner",
"email": "jean.team-owner@example.com",
"firstName": "E2E",
"lastName": "Group Owner",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.team-owner"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.mail-member",
"email": "jean.mail-member@example.com",
"firstName": "E2E",
"lastName": "Mailbox Member",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.mail-member"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.mail-administrator",
"email": "jean.mail-administrator@example.com",
"firstName": "E2E",
"lastName": "Mailbox Administrator",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.mail-administrator"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.mail-owner",
"email": "jean.mail-owner@example.com",
"firstName": "E2E",
"lastName": "Mailbox Owner",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.mail-owner"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.team-member-mail-member",
"email": "jean.team-member-mail-member@example.com",
"firstName": "E2E",
"lastName": "Group Member Mailbox Member",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.team-member-mail-member"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.team-member-mail-administrator",
"email": "jean.team-member-mail-administrator@example.com",
"firstName": "E2E",
"lastName": "Group Member Mailbox Administrator",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.team-member-mail-administrator"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.team-member-mail-owner",
"email": "jean.team-member-mail-owner@example.com",
"firstName": "E2E",
"lastName": "Group Member Mailbox Owner",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.team-member-mail-owner"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.team-administrator-mail-member",
"email": "jean.team-administrator-mail-member@example.com",
"firstName": "E2E",
"lastName": "Group Administrator Mailbox Member",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.team-administrator-mail-member"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.team-administrator-mail-administrator",
"email": "jean.team-administrator-mail-administrator@example.com",
"firstName": "E2E",
"lastName": "Group Administrator Mailbox Administrator",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.team-administrator-mail-administrator"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.team-administrator-mail-owner",
"email": "jean.team-administrator-mail-owner@example.com",
"firstName": "E2E",
"lastName": "Group Administrator Mailbox Owner",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.team-administrator-mail-owner"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.team-owner-mail-member",
"email": "jean.team-owner-mail-member@example.com",
"firstName": "E2E",
"lastName": "Group Owner Mailbox Member",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.team-owner-mail-member"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.team-owner-mail-administrator",
"email": "jean.team-owner-mail-administrator@example.com",
"firstName": "E2E",
"lastName": "Group Owner Mailbox Administrator",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.team-owner-mail-administrator"
}
],
"realmRoles": ["user"]
},
{
"username": "jean.team-owner-mail-owner",
"email": "jean.team-owner-mail-owner@example.com",
"firstName": "E2E",
"lastName": "Mailbox Owner",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password-e2e-jean.team-owner-mail-owner"
}
],
"realmRoles": ["user"]
}
],
"roles": {

51
docs/testsE2E.md Normal file
View File

@@ -0,0 +1,51 @@
# E2E tests
## Run E2E tests
``` bash
# you need the dockers to be up and running
make bootstrap
# you will need to have few accounts in the database
make demo FLUSH_ARGS='--no-input'
# run the tests
cd src/frontend/apps/e2e
yarn test:ui --workers=1
```
A new browser window will open and you will be able to run the tests.
## Available accounts
The `make demo` command creates the following accounts:
- `jean.team-<role>@example.com` where `<role>` is one of `administrator`, `member`, `owner`:
this account only belong to a team with the specified role.
- `jean.mail-<role>@example.com` where `<role>` is one of `administrator`, `member`, `owner`:
this account only have a mailbox with the specified role access.
- `jean.team-<team_role>-mail-<domain_role>@example.com` with a combination of roles as for the
previous accounts.
For each account, the password is `password-e2e-<username>`, for instance `password-e2e-jean.team-member`.
In the E2E tests you can use these accounts to benefit from there accesses,
using the `keyCloakSignIn(page, browserName, <account_name>)`. The account name is the
username without the prefix `jean.`.
``` typescript jsx
await keyCloakSignIn(page, browserName, 'mail-owner');
```
The `keyCloakSignIn` function will sign in the user on Keycloak using the proper username and password.
.. note::
This only works because the OIDC setting is set to fallback on user email.
## Add a new account
In case you need to add a new account for specific tests you need:
- to create a new user with the same format in the backend database:
update `[create_demo.py](../src/backend/demo/management/commands/create_demo.py)`
- to create a new account in Keycloak: update [realm.json](../docker/auth/realm.json)
- if the keycloak was running locally, you need to destroy its database and
restart the database and the keycloak containers.

View File

@@ -106,7 +106,7 @@ class Timeit:
return elapsed_time
def create_demo(stdout):
def create_demo(stdout): # pylint: disable=too-many-locals
"""
Create a database with demo data for developers to work in a realistic environment.
The code is engineered to create a huge number of objects fast.
@@ -190,7 +190,6 @@ def create_demo(stdout):
queue.push(
models.TeamAccess(team_id=team_id, user_id=user_id, role=role[0])
)
queue.flush()
with Timeit(stdout, "Creating domains"):
created = set()
@@ -224,6 +223,75 @@ def create_demo(stdout):
role=models.RoleChoices.OWNER,
)
)
queue.flush()
with Timeit(stdout, "Creating specific users"):
# ⚠️ Warning: this users also need to be created in the keycloak
# realm.json AND the OIDC setting to fallback on user email
# should be set to True, because we don't pilot the sub.
for role in models.RoleChoices.values:
team_user = models.User(
sub=uuid4(),
email=f"jean.team-{role}@example.com",
name=f"Jean Group {role.capitalize()}",
password="!",
is_superuser=False,
is_active=True,
is_staff=False,
language=random.choice(settings.LANGUAGES)[0],
)
queue.push(team_user)
queue.push(
models.TeamAccess(team_id=teams_ids[0], user_id=team_user.pk, role=role)
)
for role in models.RoleChoices.values:
user_with_mail = models.User(
sub=uuid4(),
email=f"jean.mail-{role}@example.com",
name=f"Jean Mail {role.capitalize()}",
password="!",
is_superuser=False,
is_active=True,
is_staff=False,
language=random.choice(settings.LANGUAGES)[0],
)
queue.push(user_with_mail)
queue.push(
mailbox_models.MailDomainAccess(
domain_id=domains_ids[0],
user_id=user_with_mail.pk,
role=role,
)
)
for team_role in models.RoleChoices.values:
for domain_role in models.RoleChoices.values:
team_mail_user = models.User(
sub=uuid4(),
email=f"jean.team-{team_role}-mail-{domain_role}@example.com",
name=f"Jean Group {team_role.capitalize()} Mail {domain_role.capitalize()}",
password="!",
is_superuser=False,
is_active=True,
is_staff=False,
language=random.choice(settings.LANGUAGES)[0],
)
queue.push(team_mail_user)
queue.push(
models.TeamAccess(
team_id=teams_ids[0], user_id=team_mail_user.pk, role=team_role
)
)
queue.push(
mailbox_models.MailDomainAccess(
domain_id=domains_ids[0],
user_id=team_mail_user.pk,
role=domain_role,
)
)
queue.flush()

View File

@@ -28,13 +28,22 @@ def test_commands_create_demo():
"""The create_demo management command should create objects as expected."""
call_command("create_demo")
assert (
models.User.objects.count() == TEST_NB_OBJECTS["users"] + 3
) # Monique Test, Jeanne Test and Jean Something (quick fix for e2e)
# Monique Test, Jeanne Test and Jean Something (quick fix for e2e)
# 3 user with team rights
# 3 user with domain rights
# 3 x 3 user with both rights
assert models.User.objects.count() == TEST_NB_OBJECTS["users"] + 3 + 3 + 3 + 9
assert models.Team.objects.count() == TEST_NB_OBJECTS["teams"]
assert models.TeamAccess.objects.count() >= TEST_NB_OBJECTS["teams"]
assert mailbox_models.MailDomain.objects.count() == TEST_NB_OBJECTS["domains"]
assert mailbox_models.MailDomainAccess.objects.count() == TEST_NB_OBJECTS["domains"]
# 3 domain access for each user with domain rights
# 3 x 3 domain access for each user with both rights
assert (
mailbox_models.MailDomainAccess.objects.count()
== TEST_NB_OBJECTS["domains"] + 3 + 9
)
def test_commands_createsuperuser():

View File

@@ -1,18 +1,27 @@
import { Page, expect } from '@playwright/test';
export const keyCloakSignIn = async (page: Page, browserName: string) => {
export const keyCloakSignIn = async (
page: Page,
browserName: string,
accountName?: string,
) => {
// Use the account name to use a specific account defined in
// the Keycloak/backend demo data creation script.
const title = await page.locator('h1').first().textContent({
timeout: 5000,
});
if (title?.includes('Sign in to your account')) {
await page
.getByRole('textbox', { name: 'username' })
.fill(`user-e2e-${browserName}`);
const username = accountName
? `jean.${accountName}`
: `user-e2e-${browserName}`;
const password = accountName
? `password-e2e-jean.${accountName}`
: `password-e2e-${browserName}`;
await page
.getByRole('textbox', { name: 'password' })
.fill(`password-e2e-${browserName}`);
if (title?.includes('Sign in to your account')) {
await page.getByRole('textbox', { name: 'username' }).fill(username);
await page.getByRole('textbox', { name: 'password' }).fill(password);
await page.click('input[type="submit"]', { force: true });
}

View File

@@ -3,12 +3,10 @@ import { expect, test } from '@playwright/test';
import { keyCloakSignIn } from './common';
test.describe('Config', () => {
test.beforeEach(async ({ page, browserName }) => {
test('it checks the config api is called', async ({ page, browserName }) => {
await page.goto('/');
await keyCloakSignIn(page, browserName);
});
test('it checks the config api is called', async ({ page }) => {
const responsePromise = page.waitForResponse(
(response) =>
response.url().includes('/config/') && response.status() === 200,
@@ -35,7 +33,12 @@ test.describe('Config', () => {
test('it checks that the config can deactivate the feature "teams"', async ({
page,
browserName,
}) => {
await page.goto('/');
// Login with a user who has the visibility on the groups
await keyCloakSignIn(page, browserName, 'team-member');
await page.route('**/api/v1.0/config/', async (route) => {
const request = route.request();
if (request.method().includes('GET')) {
@@ -61,10 +64,6 @@ test.describe('Config', () => {
}),
).toBeHidden();
await expect(
page.getByRole('button', {
name: 'Add a mail domain',
}),
).toBeVisible();
await expect(page.getByText('Mail Domains')).toBeVisible();
});
});

View File

@@ -41,7 +41,7 @@ test.describe('Keyboard navigation', () => {
const page = await browser.newPage();
await page.goto('/');
await keyCloakSignIn(page, browserName);
await keyCloakSignIn(page, browserName, 'team-owner-mail-member');
void mockApiRequests(page);

View File

@@ -10,22 +10,14 @@ test.describe('Language', () => {
});
test('checks the language picker', async ({ page }) => {
await expect(
page.getByRole('button', {
name: 'Create a new team',
}),
).toBeVisible();
await expect(page.getByText('Groups')).toBeVisible();
const header = page.locator('header').first();
await header.getByRole('combobox').getByText('EN').click();
await header.getByRole('option', { name: 'FR' }).click();
await expect(header.getByRole('combobox').getByText('FR')).toBeVisible();
await expect(
page.getByRole('button', {
name: 'Créer un nouveau groupe',
}),
).toBeVisible();
await expect(page.getByText('Groupes')).toBeVisible();
});
test('checks lang attribute of html tag updates when user changes language', async ({

View File

@@ -130,7 +130,8 @@ const navigateToMailboxCreationFormForMailDomainFr = async (
test.describe('Mail domain create mailbox', () => {
test.beforeEach(async ({ page, browserName }) => {
await page.goto('/');
await keyCloakSignIn(page, browserName);
// Login with a user who has the visibility on the mail domains
await keyCloakSignIn(page, browserName, 'mail-member');
});
test('checks user can create a mailbox when he has post ability', async ({

View File

@@ -113,14 +113,13 @@ const assertFilledMailboxesTableElementsAreVisible = async (
};
test.describe('Mail domain', () => {
test.beforeEach(async ({ page, browserName }) => {
await page.goto('/');
await keyCloakSignIn(page, browserName);
});
test('redirects to 404 page when the mail domain requested does not exist', async ({
page,
browserName,
}) => {
await page.goto('/');
await keyCloakSignIn(page, browserName);
await page.route('**/api/v1.0/mail-domains/?page=*', async (route) => {
await route.fulfill({
json: {
@@ -143,6 +142,11 @@ test.describe('Mail domain', () => {
});
test.describe('user is administrator or owner', () => {
test.beforeEach(async ({ page, browserName }) => {
await page.goto('/');
await keyCloakSignIn(page, browserName, 'mail-owner');
});
test.describe('mail domain is enabled', () => {
const mailDomainsFixtures: MailDomain[] = [
{
@@ -479,6 +483,11 @@ test.describe('Mail domain', () => {
});
test.describe('user is member', () => {
test.beforeEach(async ({ page, browserName }) => {
await page.goto('/');
await keyCloakSignIn(page, browserName, 'mail-member');
});
test.describe('mail domain is enabled', () => {
const mailDomainsFixtures: MailDomain[] = [
{

View File

@@ -75,7 +75,7 @@ test.describe('Mail domains', () => {
test.describe('checks all the elements are visible', () => {
test.beforeEach(async ({ page, browserName }) => {
await page.goto('/');
await keyCloakSignIn(page, browserName);
await keyCloakSignIn(page, browserName, 'mail-member');
});
test('checks the sort button', async ({ page }) => {

View File

@@ -4,7 +4,7 @@ import { addNewMember, createTeam, keyCloakSignIn } from './common';
test.beforeEach(async ({ page, browserName }) => {
await page.goto('/');
await keyCloakSignIn(page, browserName);
await keyCloakSignIn(page, browserName, 'team-member');
});
test.describe('Members Delete', () => {
@@ -17,9 +17,7 @@ test.describe('Members Delete', () => {
const table = page.getByLabel('List members card').getByRole('table');
const cells = table.getByRole('row').nth(1).getByRole('cell');
await expect(cells.nth(1)).toHaveText(
new RegExp(`E2E ${browserName}`, 'i'),
);
await expect(cells.nth(1)).toHaveText('Jean Group Member');
await cells.nth(4).getByLabel('Member options').click();
await page.getByLabel('Open the modal to delete this member').click();
@@ -46,7 +44,7 @@ test.describe('Members Delete', () => {
// find row where regexp match the name
const cells = table
.getByRole('row')
.filter({ hasText: new RegExp(`E2E ${browserName}`, 'i') })
.filter({ hasText: 'E2E Group Member' })
.getByRole('cell');
await cells.nth(4).getByLabel('Member options').click();
await page.getByLabel('Open the modal to delete this member').click();
@@ -118,7 +116,7 @@ test.describe('Members Delete', () => {
// find row where regexp match the name
const myCells = table
.getByRole('row')
.filter({ hasText: new RegExp(`E2E ${browserName}`, 'i') })
.filter({ hasText: 'E2E Group Member' })
.getByRole('cell');
await myCells.nth(4).getByLabel('Member options').click();
@@ -148,7 +146,7 @@ test.describe('Members Delete', () => {
// find row where regexp match the name
const myCells = table
.getByRole('row')
.filter({ hasText: new RegExp(`E2E ${browserName}`, 'i') })
.filter({ hasText: 'E2E Group Member' })
.getByRole('cell');
await myCells.nth(4).getByLabel('Member options').click();

View File

@@ -4,7 +4,7 @@ import { createTeam, keyCloakSignIn } from './common';
test.beforeEach(async ({ page, browserName }) => {
await page.goto('/');
await keyCloakSignIn(page, browserName);
await keyCloakSignIn(page, browserName, 'team-owner-mail-member');
});
test.describe('Menu', () => {