Skip to content

Commit

Permalink
Merge pull request #79 from c4dt/playwright
Browse files Browse the repository at this point in the history
Automated form list tests
  • Loading branch information
PascalinDe authored Jan 18, 2024
2 parents a5e99b6 + d28bec3 commit c8339fa
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 12 deletions.
4 changes: 2 additions & 2 deletions web/frontend/src/layout/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const MobileMenu = ({ authCtx, handleLogout, fctx, t }) => (
<XIcon className="h-6 w-6" aria-hidden="true" />
</Popover.Button>
</div>
<div>
<div data-testid="mobileMenuLogo">
<img className="h-10 w-auto" src={logo} alt="Workflow" />
</div>
</div>
Expand Down Expand Up @@ -177,7 +177,7 @@ const RightSideNavBar = ({ authCtx, handleLogout, handleChangeId, fctx, t }) =>

const LeftSideNavBar = ({ authCtx, t }) => (
<div className="flex-1 flex items-center justify-center md:justify-start">
<div className="flex-shrink-0 flex items-center">
<div data-testid="leftSideNavBarLogo" className="flex-shrink-0 flex items-center">
<NavLink to={ROUTE_HOME}>
<img className="hidden lg:block h-10 w-auto" src={logo} alt="Workflow" />
</NavLink>
Expand Down
2 changes: 1 addition & 1 deletion web/frontend/src/pages/form/components/QuickAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type QuickActionProps = {

const QuickAction: FC<QuickActionProps> = ({ status, formID }) => {
return (
<div>
<div data-testid="quickAction">
{status === Status.Open && <VoteButton status={status} formID={formID} />}
{status === Status.ResultAvailable && <ResultButton status={status} formID={formID} />}
</div>
Expand Down
93 changes: 91 additions & 2 deletions web/frontend/tests/formIndex.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { expect, test } from '@playwright/test';
import { default as i18n } from 'i18next';
import { assertHasFooter, assertHasNavBar, initI18n, setUp } from './shared';
import { mockEvoting, mockPersonalInfo } from './mocks';
import { assertHasFooter, assertHasNavBar, initI18n, logIn, setUp, translate } from './shared';
import { SCIPER_ADMIN, SCIPER_USER, mockEvoting, mockPersonalInfo } from './mocks';
import Forms from './json/formList.json';
import User from './json/personal_info/789012.json';
import Admin from './json/personal_info/123456.json';

initI18n();

async function goForward(page: page) {
await page.getByRole('button', { name: i18n.t('next') }).click();
}

test.beforeEach(async ({ page }) => {
// mock empty list per default
await mockEvoting(page);
Expand Down Expand Up @@ -66,3 +73,85 @@ test('Assert pagination works correctly for non-empty list', async ({ page }) =>
await expect(previous).toBeDisabled();
await expect(next).toBeEnabled();
});

test('Assert no forms are displayed for empty list', async ({ page }) => {
// 1 header row
await expect
.poll(async () => {
const rows = await page.getByRole('table').getByRole('row');
return rows.all();
})
.toHaveLength(1);
});

async function assertQuickAction(row: locator, form: object, sciper?: string) {
const user = sciper === SCIPER_USER ? User : (sciper === SCIPER_ADMIN ? Admin : undefined); // eslint-disable-line
const quickAction = row.getByTestId('quickAction');
switch (form.Status) {
case 1:
// only authenticated user w/ right to vote sees 'vote' button
if (
user !== undefined &&
form.FormID in user.authorization &&
user.authorization[form.FormID].includes('vote')
) {
await expect(quickAction).toHaveText(i18n.t('vote'));
await expect(await quickAction.getByRole('link')).toHaveAttribute(
'href',
`/ballot/show/${form.FormID}`
);
await expect(quickAction).toBeVisible();
} else {
await expect(quickAction).toBeHidden();
}
break;
case 5:
// any user can see the results of a past election
await expect(quickAction).toHaveText(i18n.t('seeResult'));
await expect(await quickAction.getByRole('link')).toHaveAttribute(
'href',
`/forms/${form.FormID}/result`
);
break;
default:
await expect(quickAction).toBeHidden();
}
}

test('Assert forms are displayed correctly for unauthenticated user', async ({ page }) => {
await mockEvoting(page, false);
await page.reload();
const table = await page.getByRole('table');
for (let form of Forms.Forms.slice(0, -1)) {
let name = translate(form.Title);
let row = await table.getByRole('row', { name: name });
await expect(row).toBeVisible();
// row entry leads to form view
let link = await row.getByRole('link', { name: name });
await expect(link).toBeVisible();
await expect(link).toHaveAttribute('href', `/forms/${form.FormID}`);
await assertQuickAction(row, form);
}
await goForward(page);
let row = await table.getByRole('row', { name: translate(Forms.Forms.at(-1).Title) });
await expect(row).toBeVisible();
await assertQuickAction(row, Forms.Forms.at(-1));
});

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 page.reload();
const table = await page.getByRole('table');
for (let form of Forms.Forms.slice(0, -1)) {
let row = await table.getByRole('row', { name: translate(form.Title) });
await assertQuickAction(row, form, sciper);
}
await goForward(page);
await assertQuickAction(
await table.getByRole('row', { name: translate(Forms.Forms.at(-1).Title) }),
Forms.Forms.at(-1)
);
}
});
4 changes: 2 additions & 2 deletions web/frontend/tests/json/formList.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@
"Fr": "",
"De": ""
},
"Status": 0,
"Pubkey": ""
"Status": 1,
"Pubkey": "348f56a444e1b75214a9c675587222099007ce739a04651667c054d9be626e07"
},
{
"FormID": "1269a8507dc316a9ec983ede527705078bfef2b151a49f7ffae6e903ef1bb38f",
Expand Down
25 changes: 24 additions & 1 deletion web/frontend/tests/json/personal_info/123456.json
Original file line number Diff line number Diff line change
@@ -1 +1,24 @@
{"sciper":123456,"lastName":"123456","firstName":"sciper-#","isLoggedIn":true,"authorization":{"roles":["add","list","remove"],"proxies":["post","put","delete"],"election":["create"]}}
{
"sciper": 123456,
"lastName": "123456",
"firstName": "sciper-#",
"isLoggedIn": true,
"authorization": {
"roles": [
"add",
"list",
"remove"
],
"proxies": [
"post",
"put",
"delete"
],
"election": [
"create"
],
"fdf8bfb702e8883e330a2b303b24212b6fc16df5a53a097998b77ba74632dc72": ["own"],
"ed26713245824d44ee46ec90507ef521962f2313706934cdfe76ff1823738109": ["vote"],
"9f50ad723805a6419ba1a9f83dd0aa582f3e13b94f14727cd0c8c01744e0dba2": ["vote", "own"]
}
}
11 changes: 10 additions & 1 deletion web/frontend/tests/json/personal_info/789012.json
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
{"sciper":789012,"lastName":"789012","firstName":"sciper-#","isLoggedIn":true,"authorization":{}}
{
"sciper": 789012,
"lastName": "789012",
"firstName": "sciper-#",
"isLoggedIn": true,
"authorization": {
"fdf8bfb702e8883e330a2b303b24212b6fc16df5a53a097998b77ba74632dc72": ["vote"],
"ed26713245824d44ee46ec90507ef521962f2313706934cdfe76ff1823738109": ["vote"]
}
}
5 changes: 2 additions & 3 deletions web/frontend/tests/navbar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ test('Assert cookie is set', async ({ page }) => {
});

test('Assert D-Voting logo is present', async ({ page }) => {
const logo = await page.getByAltText(i18n.t('Workflow'));
const logo = await page.getByTestId('leftSideNavBarLogo');
await expect(logo).toBeVisible();
await logo.click();
await expect(page).toHaveURL('/');
await expect(await logo.getByRole('link')).toHaveAttribute('href', '/');
});

test('Assert link to form table is present', async ({ page }) => {
Expand Down
13 changes: 13 additions & 0 deletions web/frontend/tests/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,16 @@ export async function assertHasNavBar(page: page) {
export async function assertHasFooter(page: page) {
await expect(page.getByTestId('footer')).toBeVisible();
}

export function translate(internationalizable: object) {
switch (i18n.language) {
case 'en':
return internationalizable.En;
case 'fr':
return internationalizable.Fr || internationalizable.En;
case 'de':
return internationalizable.De || internationalizable.En;
default:
return internationalizable.En;
}
}

0 comments on commit c8339fa

Please sign in to comment.