Skip to content

Commit

Permalink
Merge pull request #89 from c4dt/72
Browse files Browse the repository at this point in the history
clean up test directory, and initial add form management tests
  • Loading branch information
PascalinDe authored Jan 25, 2024
2 parents fda3bcd + 7fcd939 commit a2a262a
Show file tree
Hide file tree
Showing 30 changed files with 801 additions and 68 deletions.
1 change: 1 addition & 0 deletions scripts/run_docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ function init_dela() {
function local_admin() {
echo "adding local user $REACT_APP_SCIPER_ADMIN to admins";
docker compose exec backend npx cli addAdmin --sciper "$REACT_APP_SCIPER_ADMIN";
docker compose exec backend npx cli addAdmin --sciper 987654;
docker compose restart backend;
}

Expand Down
3 changes: 2 additions & 1 deletion web/frontend/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require("dotenv").config({ path: "./../../.env" });
export default defineConfig({
testDir: './tests',
/* Run tests in files in parallel */
fullyParallel: true,
fullyParallel: false,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
Expand All @@ -24,6 +24,7 @@ export default defineConfig({
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},
workers: 1,

/* Configure projects for major browsers */
projects: [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { DocumentAddIcon } from '@heroicons/react/outline';
import { useTranslation } from 'react-i18next';
import { isManager } from './utils';
import { AuthContext } from 'index';
import { useContext } from 'react';
import { useTranslation } from 'react-i18next';

const SUBJECT_ELECTION = 'election';
const ACTION_CREATE = 'create';

const AddVotersButton = ({ handleAddVoters }) => {
const authCtx = useContext(AuthContext);
const AddVotersButton = ({ handleAddVoters, formID }) => {
const { t } = useTranslation();
const { authorization, isLogged } = useContext(AuthContext);

return (
authCtx.isAllowed(SUBJECT_ELECTION, ACTION_CREATE) && (
<button onClick={handleAddVoters}>
isManager(formID, authorization, isLogged) && (
<button data-testid="addVotersButton" onClick={handleAddVoters}>
<div className="whitespace-nowrap inline-flex items-center justify-center px-4 py-1 mr-2 border border-gray-300 text-sm rounded-full font-medium text-gray-700 hover:text-red-500">
<DocumentAddIcon className="-ml-1 mr-2 h-5 w-5" aria-hidden="true" />
{t('addVoters')}
Expand Down
11 changes: 11 additions & 0 deletions web/frontend/src/pages/form/components/ActionButtons/utils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ID } from './../../../../types/configuration';

export function isManager(formID: ID, authorization: Map<String, String[]>, isLogged: boolean) {
return (
isLogged && // must be logged in
authorization.has('election') &&
authorization.get('election').includes('create') && // must be able to create elections
authorization.has(formID) &&
authorization.get(formID).includes('own') // must own the election
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ const useChangeAction = (
<>
<OpenButton status={status} handleOpen={handleOpen} ongoingAction={ongoingAction} />
<DeleteButton handleDelete={handleDelete} />
<AddVotersButton handleAddVoters={handleAddVoters} />
<AddVotersButton handleAddVoters={handleAddVoters} formID={formID} />
</>
);
case Status.Open:
Expand All @@ -518,7 +518,7 @@ const useChangeAction = (
/>
<VoteButton status={status} formID={formID} />
<DeleteButton handleDelete={handleDelete} />
<AddVotersButton handleAddVoters={handleAddVoters} />
<AddVotersButton handleAddVoters={handleAddVoters} formID={formID} />
</>
);
case Status.Closed:
Expand Down
2 changes: 1 addition & 1 deletion web/frontend/tests/footer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect, test } from '@playwright/test';
import { default as i18n } from 'i18next';
import { initI18n, setUp } from './shared';
import { mockPersonalInfo } from './mocks';
import { mockPersonalInfo } from './mocks/api';

initI18n();

Expand Down
15 changes: 8 additions & 7 deletions web/frontend/tests/formIndex.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { expect, test } from '@playwright/test';
import { default as i18n } from 'i18next';
import { assertHasFooter, assertHasNavBar, initI18n, logIn, setUp, translate } from './shared';
import { SCIPER_ADMIN, SCIPER_USER, mockEvoting, mockPersonalInfo } from './mocks';
import { SCIPER_ADMIN, SCIPER_USER, mockPersonalInfo } from './mocks/api';
import { mockForms } from './mocks/evoting';
import Forms from './json/formList.json';
import User from './json/personal_info/789012.json';
import Admin from './json/personal_info/123456.json';
import User from './json/api/personal_info/789012.json';
import Admin from './json/api/personal_info/123456.json';

initI18n();

Expand All @@ -14,7 +15,7 @@ async function goForward(page: page) {

test.beforeEach(async ({ page }) => {
// mock empty list per default
await mockEvoting(page);
await mockForms(page);
await mockPersonalInfo(page);
await setUp(page, '/form/index');
});
Expand Down Expand Up @@ -48,7 +49,7 @@ test('Assert pagination works correctly for empty list', async ({ page }) => {

test('Assert pagination works correctly for non-empty list', async ({ page }) => {
// mock non-empty list w/ 11 elements i.e. 2 pages
await mockEvoting(page, false);
await mockForms(page, false);
await page.reload();
const next = await page.getByRole('button', { name: i18n.t('next') });
const previous = await page.getByRole('button', { name: i18n.t('previous') });
Expand Down Expand Up @@ -119,7 +120,7 @@ async function assertQuickAction(row: locator, form: object, sciper?: string) {
}

test('Assert forms are displayed correctly for unauthenticated user', async ({ page }) => {
await mockEvoting(page, false);
await mockForms(page, false);
await page.reload();
const table = await page.getByRole('table');
for (let form of Forms.Forms.slice(0, -1)) {
Expand All @@ -141,7 +142,7 @@ test('Assert forms are displayed correctly for unauthenticated user', async ({ p
test('Assert quick actions are displayed correctly for authenticated users', async ({ page }) => {
for (let sciper of [SCIPER_USER, SCIPER_ADMIN]) {
await logIn(page, sciper);
await mockEvoting(page, false);
await mockForms(page, false);
await page.reload();
const table = await page.getByRole('table');
for (let form of Forms.Forms.slice(0, -1)) {
Expand Down
76 changes: 76 additions & 0 deletions web/frontend/tests/forms.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { expect, test } from '@playwright/test';
import { assertHasFooter, assertHasNavBar, initI18n, logIn, setUp } from './shared';
import {
SCIPER_ADMIN,
SCIPER_OTHER_ADMIN,
SCIPER_USER,
mockPersonalInfo,
mockProxies,
} from './mocks/api';
import { FORMID, mockDKGActors, mockFormsFormID } from './mocks/evoting';

initI18n();

// main elements

async function setUpMocks(
page: page,
formStatus: number,
dkgActorsStatus: number,
initialized?: boolean
) {
// the nodes must have been initialized if they changed state
initialized = initialized || dkgActorsStatus > 0;
await mockFormsFormID(page, formStatus);
for (const i of [0, 1, 2, 3]) {
await mockProxies(page, i);
}
await mockDKGActors(page, dkgActorsStatus, initialized);
await mockPersonalInfo(page);
}

test.beforeEach(async ({ page }) => {
// mock empty list per default
setUpMocks(page, 0, 0, false);
await setUp(page, `/forms/${FORMID}`);
});

test('Assert navigation bar is present', async ({ page }) => {
await assertHasNavBar(page);
});

test('Assert footer is present', async ({ page }) => {
await assertHasFooter(page);
});

async function assertIsOnlyVisibleToOwner(page: page, locator: locator) {
await test.step('Assert is hidden to unauthenticated user', async () => {
await expect(locator).toBeHidden();
});
await test.step('Assert is hidden to authenticated non-admin user', async () => {
await logIn(page, SCIPER_USER);
await expect(locator).toBeHidden();
});
await test.step('Assert is hidden to non-owner admin', async () => {
await logIn(page, SCIPER_ADMIN);
await expect(locator).toBeHidden();
});
await test.step('Assert is visible to owner admin', async () => {
await logIn(page, SCIPER_OTHER_ADMIN);
await expect(locator).toBeVisible();
});
}

async function assertIsOnlyVisibleToOwnerStates(page: page, locator: locator, states: Array) {
for (const i of states) {
await test.step(`Assert is only visible to owner in state ${i}`, async () => {
await setUpMocks(page, i, 6);
await page.reload({ waitUntil: 'networkidle' });
await assertIsOnlyVisibleToOwner(page, locator);
});
}
}

test('Assert "Add voters" button is only visible to owner', async ({ page }) => {
await assertIsOnlyVisibleToOwnerStates(page, page.getByTestId('addVotersButton'), [0, 1]);
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
],
"fdf8bfb702e8883e330a2b303b24212b6fc16df5a53a097998b77ba74632dc72": ["own"],
"ed26713245824d44ee46ec90507ef521962f2313706934cdfe76ff1823738109": ["vote"],
"9f50ad723805a6419ba1a9f83dd0aa582f3e13b94f14727cd0c8c01744e0dba2": ["vote", "own"]
"9f50ad723805a6419ba1a9f83dd0aa582f3e13b94f14727cd0c8c01744e0dba2": ["vote", "own"],
"b63bcb854121051f2d8cff04bf0ac9b524b534b704509a16a423448bde3321b4": ["vote"]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"isLoggedIn": true,
"authorization": {
"fdf8bfb702e8883e330a2b303b24212b6fc16df5a53a097998b77ba74632dc72": ["vote"],
"ed26713245824d44ee46ec90507ef521962f2313706934cdfe76ff1823738109": ["vote"]
"ed26713245824d44ee46ec90507ef521962f2313706934cdfe76ff1823738109": ["vote"],
"b63bcb854121051f2d8cff04bf0ac9b524b534b704509a16a423448bde3321b4": ["vote"]
}
}
25 changes: 25 additions & 0 deletions web/frontend/tests/json/api/personal_info/987654.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"sciper": 987654,
"lastName": "987654",
"firstName": "sciper-#",
"isLoggedIn": true,
"authorization": {
"roles": [
"add",
"list",
"remove"
],
"proxies": [
"post",
"put",
"delete"
],
"election": [
"create"
],
"fdf8bfb702e8883e330a2b303b24212b6fc16df5a53a097998b77ba74632dc72": ["own"],
"ed26713245824d44ee46ec90507ef521962f2313706934cdfe76ff1823738109": ["vote", "own"],
"9f50ad723805a6419ba1a9f83dd0aa582f3e13b94f14727cd0c8c01744e0dba2": ["vote"],
"b63bcb854121051f2d8cff04bf0ac9b524b534b704509a16a423448bde3321b4": ["own"]
}
}
4 changes: 4 additions & 0 deletions web/frontend/tests/json/api/proxies/dela-worker-0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"NodeAddr": "grpc://dela-worker-0:2000",
"Proxy": "http://172.19.44.254:8080"
}
4 changes: 4 additions & 0 deletions web/frontend/tests/json/api/proxies/dela-worker-1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"NodeAddr": "grpc://dela-worker-1:2000",
"Proxy": "http://172.19.44.253:8080"
}
4 changes: 4 additions & 0 deletions web/frontend/tests/json/api/proxies/dela-worker-2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"NodeAddr": "grpc://dela-worker-2:2000",
"Proxy": "http://172.19.44.252:8080"
}
4 changes: 4 additions & 0 deletions web/frontend/tests/json/api/proxies/dela-worker-3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"NodeAddr": "grpc://dela-worker-3:2000",
"Proxy": "http://172.19.44.251:8080"
}
9 changes: 9 additions & 0 deletions web/frontend/tests/json/evoting/dkgActors/certified.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Status": 6,
"Error": {
"Title": "",
"Code": 0,
"Message": "",
"Args": null
}
}
9 changes: 9 additions & 0 deletions web/frontend/tests/json/evoting/dkgActors/initialized.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Status": 0,
"Error": {
"Title": "",
"Code": 0,
"Message": "",
"Args": null
}
}
9 changes: 9 additions & 0 deletions web/frontend/tests/json/evoting/dkgActors/setup.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Status": 1,
"Error": {
"Title": "",
"Code": 0,
"Message": "",
"Args": null
}
}
10 changes: 10 additions & 0 deletions web/frontend/tests/json/evoting/dkgActors/uninitialized.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Title": "not found",
"Code": 404,
"Message": "A problem occurred on the proxy",
"Args": {
"error": "actor not found",
"method": "GET",
"url": "/evoting/services/dkg/actors/d3319c58a3bea17dafe61168610757b9a7bb0d922c1f2aa30b8ad537646b1c07"
}
}
64 changes: 64 additions & 0 deletions web/frontend/tests/json/evoting/forms/closed.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"FormID": "b63bcb854121051f2d8cff04bf0ac9b524b534b704509a16a423448bde3321b4",
"Configuration": {
"Title": {
"En": "Colours",
"Fr": "",
"De": ""
},
"Scaffold": [
{
"ID": "yOakwFnR",
"Title": {
"En": "Colours",
"Fr": "Couleurs",
"De": "Farben"
},
"Order": [
"CLgNiLbC"
],
"Subjects": [],
"Selects": [
{
"ID": "CLgNiLbC",
"Title": {
"En": "RGB",
"Fr": "RGB",
"De": "RGB"
},
"MaxN": 2,
"MinN": 1,
"Choices": [
"{\"en\":\"Red\",\"fr\":\"Rouge\",\"de\":\"Rot\"}",
"{\"en\":\"Green\",\"fr\":\"Vert\",\"de\":\"Grün\"}",
"{\"en\":\"Blue\",\"fr\":\"Bleu\",\"de\":\"Blau\"}"
],
"Hint": {
"En": "",
"Fr": "",
"De": ""
}
}
],
"Ranks": [],
"Texts": []
}
]
},
"Status": 2,
"Pubkey": "612fdc867be1a5faccf16e5aed946880005840ee04aaa382fe181a2b46dc9a24",
"Result": [],
"Roster": [
"grpc://dela-worker-0:2000",
"grpc://dela-worker-1:2000",
"grpc://dela-worker-2:2000",
"grpc://dela-worker-3:2000"
],
"ChunksPerBallot": 1,
"BallotSize": 23,
"Voters": [
"oUItDdhhEE",
"WZyqP1gssL",
"K7ZNvumBVc"
]
}
Loading

0 comments on commit a2a262a

Please sign in to comment.