diff --git a/.env.example b/.env.example index 21127c5..20cb538 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,5 @@ -E2E_EMAIL = "a@a.com" -E2E_PASSWORD = "a" \ No newline at end of file +MAINUSER_PASS="a" +MAINUSER_MAIL="a@a.org" +SECONDUSER_PASS="b" +SECONDUSER_MAIL="b@b.org" +LINK="localhost:4000" diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 0000000..3eb1314 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,27 @@ +name: Playwright Tests +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Run Playwright tests + run: npx playwright test + - uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index 71b935d..b6ecfd9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,11 @@ -.env node_modules test-results package-lock.json -.vscode \ No newline at end of file +.env +.vscode + +# Playwright +/playwright-report/ +/blob-report/ +/playwright/.cache/ +/playwright/.auth/ diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..222861c --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "tabWidth": 2, + "useTabs": false +} diff --git a/Chat.test.ts b/Chat.test.ts index a07de94..86d20fe 100644 --- a/Chat.test.ts +++ b/Chat.test.ts @@ -1,20 +1,17 @@ import { test, expect, firefox, chromium } from '@playwright/test'; -import { login, logout, randomString } from './generic'; +import { idfy, login, logout, newWindow, randomString, register } from './generic'; import { createGroup, deleteGroup, gotoGroup, joinGroup } from './group'; +import 'dotenv/config' test('Group-Chat', async ({ page }) => { await login(page); - const rand = Math.random().toString(36).slice(2, 10); - const group = { name: 'Test Group Chat' + rand, public: true }; + const group = { name: 'test-group-chat' + randomString(), public: true }; await createGroup(page, group); - const browser = await chromium.launch(); - const bContext = await browser.newContext(); - const bPage = await bContext.newPage(); - - await login(bPage, { email: 'b@b.se', password: 'b' }); + const bPage = await newWindow(); + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS }); await joinGroup(bPage, group); await page.reload(); @@ -38,17 +35,17 @@ test('Group-Chat', async ({ page }) => { await bPage.getByRole('button', { name: 'open chat' }).click(); await bPage.getByPlaceholder('Search chatters').click(); await bPage.getByPlaceholder('Search chatters').fill(group.name); - await bPage.getByRole('button', { name: group.name }).click(); + await bPage.getByRole('button', { name: group.name }).first().click(); await page.waitForTimeout(300); await bPage.getByPlaceholder('Write a message...').fill('Hello!! :D'); await bPage.getByPlaceholder('Write a message...').press('Enter'); await page.waitForTimeout(300); - expect(page.getByText('Hello!! :D').nth(1)).toBeVisible(); - expect(page.getByText('Hello!! :D').nth(2)).toBeVisible(); + await expect(page.getByText('Hello!! :D').nth(1)).toBeVisible(); + await expect(page.getByText('Hello!! :D').nth(2)).toBeVisible(); - expect(bPage.getByText('Hello!! :D').nth(1)).toBeVisible(); - expect(bPage.getByText('Hello!! :D').nth(2)).toBeVisible(); + await expect(bPage.getByText('Hello!! :D').nth(1)).toBeVisible(); + await expect(bPage.getByText('Hello!! :D').nth(2)).toBeVisible(); await gotoGroup(page, group); await deleteGroup(page, group); @@ -65,7 +62,7 @@ test('Direct-Chat-Via-Group', async ({ page }) => { const bContext = await browser.newContext(); const bPage = await bContext.newPage(); - await login(bPage, { email: 'b@b.se', password: 'b' }); + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS }); await joinGroup(bPage, group); await gotoGroup(bPage, group); @@ -92,3 +89,131 @@ test('Direct-Chat-Via-Group', async ({ page }) => { await deleteGroup(page, group); }); + +test('Workgroup-Chat', async ({ page }) => { + await login(page); + + const group = { name: 'Test Group Chat Workgroup' + randomString(), public: true }; + + await createGroup(page, group); + + const bPage = await newWindow(); + + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS }); + await joinGroup(bPage, group); + await gotoGroup(bPage, group); + + await page.getByRole('button', { name: 'Work Groups' }).click(); + await page.getByRole('button', { name: '+ Add Workgroup' }).click(); + await page.getByLabel('Name').click(); + + const workgroup = 'Workgroup for chatting in yay' + randomString() + await page.getByLabel('Name').fill(workgroup); + await page.getByRole('button', { name: 'Create', exact: true }).click(); + await page.getByRole('button', { name: 'Join', exact: true }).click(); + + await bPage.getByRole('button', { name: 'Work Groups' }).click(); + await bPage.getByRole('button', { name: 'Join', exact: true }).click(); + + await page.reload(); + await page.getByRole('button', { name: 'open chat' }).click(); + + await page.getByPlaceholder('Search chatters').click(); + await page.getByPlaceholder('Search chatters').fill(workgroup); + await page.getByRole('button', { name: workgroup }).click(); + await page.getByPlaceholder('Write a message...').click(); + await page.getByPlaceholder('Write a message...').fill('Hello!! :D'); + await page.locator('form > button:nth-child(2)').click(); + await page.getByPlaceholder('Write a message...').click(); + + // await bPage.reload(); + await bPage.getByRole('button', { name: 'open chat' }).click(); + await bPage.getByPlaceholder('Search chatters').click(); + await bPage.getByPlaceholder('Search chatters').fill(workgroup); + await bPage.getByRole('button', { name: workgroup }).click(); + await bPage.getByPlaceholder('Write a message...').fill('Hello!! :D'); + await bPage.getByPlaceholder('Write a message...').press('Enter'); + + await expect(page.getByText('Hello!! :D').nth(1)).toBeVisible(); + await expect(page.getByText('Hello!! :D').nth(2)).toBeVisible(); + + await expect(bPage.getByText('Hello!! :D').nth(1)).toBeVisible(); + await expect(bPage.getByText('Hello!! :D').nth(2)).toBeVisible(); + + await page.getByRole('button', { name: 'Close modal' }).click(); + +}); + +// TODO Fix this, will require finessing with registring new users +test('Group-Chat-Creation', async ({ page }) => { + await login(page) + + // Testing error functionality + await page.getByRole('button', { name: 'open chat' }).click(); + await page.getByRole('button', { name: '+ New Group' }).click(); + await page.getByRole('button', { name: 'Cancel' }).click(); + await page.getByRole('button', { name: '+ New Group' }).click(); + await page.getByRole('button', { name: 'Confirm' }).click(); + await expect(page.getByText('Failed to created group chat')).toBeVisible(); + + // Have other users chat + const bPage = await newWindow(); + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS }) + + const cPage = await newWindow(); + const { username } = await register(cPage); + + // Creating the group and checking that it was created + // await page.getByRole('button', { name: 'avatar bb, a_edited' }).click(); + await page.locator(`[id="chat-${process.env.SECONDUSER_NAME},-${process.env.MAINUSER_NAME}"]`).getByRole('button', { name: 'Add User' }).click(); + + await page.getByRole('button', { name: 'avatar + Invite user' }).nth(1).click(); + await page.getByRole('textbox', { name: 'User to invite' }).click(); + await page.getByRole('textbox', { name: 'User to invite' }).fill(username); + await page.getByRole('button', { name: 'Add Me!', exact: true }).click(); + await page.getByRole('button', { name: 'Close modal' }).nth(3).click(); + await page.getByRole('button', { name: 'Confirm' }).click(); + await expect(page.getByText('Failed to created group chat')).not.toBe; + + + const groupname = `${process.env.MAINUSER_NAME}, ${process.env.SECONDUSER_NAME}, ${username}`; + // Write messages and check that they are visible + await page.getByPlaceholder('Write a message...').click(); + await page.getByPlaceholder('Write a message...').fill('Hello!! :D'); + await page.waitForTimeout(300); + await page.locator('form > button:nth-child(2)').click(); + await page.getByPlaceholder('Write a message...').click(); + await page.waitForTimeout(300); + + await bPage.getByRole('button', { name: 'open chat' }).click(); + await bPage.getByPlaceholder('Search chatters').click(); + await bPage.getByPlaceholder('Search chatters').fill(groupname); + await bPage.getByRole('button', { name: groupname }).first().click(); + await page.waitForTimeout(300); + await bPage.getByPlaceholder('Write a message...').fill('Hello!! :D'); + await bPage.getByPlaceholder('Write a message...').press('Enter'); + await page.waitForTimeout(300); + + await cPage.getByRole('button', { name: 'open chat' }).click(); + await cPage.getByPlaceholder('Search chatters').click(); + await cPage.getByPlaceholder('Search chatters').fill(groupname); + await cPage.getByRole('button', { name: groupname }).first().click(); + await page.waitForTimeout(300); + await cPage.getByPlaceholder('Write a message...').fill('Hello!! :D'); + await cPage.getByPlaceholder('Write a message...').press('Enter'); + await page.waitForTimeout(300); + + + await expect(page.getByText('Hello!! :D').nth(1)).toBeVisible(); + await expect(page.getByText('Hello!! :D').nth(2)).toBeVisible(); + await expect(page.getByText('Hello!! :D').nth(3)).toBeVisible(); + + await expect(bPage.getByText('Hello!! :D').nth(1)).toBeVisible(); + await expect(bPage.getByText('Hello!! :D').nth(2)).toBeVisible(); + await expect(bPage.getByText('Hello!! :D').nth(3)).toBeVisible(); + + await expect(cPage.getByText('Hello!! :D').nth(1)).toBeVisible(); + await expect(cPage.getByText('Hello!! :D').nth(2)).toBeVisible(); + await expect(cPage.getByText('Hello!! :D').nth(3)).toBeVisible(); + +}) \ No newline at end of file diff --git a/Delegation.test.ts b/Delegation.test.ts index 7baa2c1..7f794d8 100644 --- a/Delegation.test.ts +++ b/Delegation.test.ts @@ -3,6 +3,8 @@ import { login, randomString } from './generic'; import { createPoll, createProposal, fastForward, goToPost, vote } from './poll'; import { createGroup, deleteGroup, gotoGroup, joinGroup } from './group'; import { becomeDelegate } from './delegation'; +import { idfy } from './generic'; +import 'dotenv/config' import { assignPermission, createPermission } from './permission'; import { idfy } from './generic'; @@ -22,7 +24,7 @@ test('Become-Delegate', async ({ page }) => { test('Delegation-Poll', async ({ page }) => { await login(page); - const group = { name: 'Test Group Delegation', public: true }; + const group = { name: 'Test Group Delegation' + randomString(), public: true }; await createGroup(page, group); @@ -34,12 +36,15 @@ test('Delegation-Poll', async ({ page }) => { const bContext = await browser.newContext(); const bPage = await bContext.newPage(); - await login(bPage, { email: 'b@b.se', password: 'b' }); + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS }); await joinGroup(bPage, group); await page.waitForTimeout(1000); - await bPage.getByRole('link', { name: 'Delegations' }).click(); - await bPage.locator('#delegate-group-select').selectOption({ label: group.name }); + await bPage.getByRole('button', { name: 'Delegations' }).click(); + // await bPage.locator('#delegate-group-select').selectOption({ label: group.name }); + await bPage.getByRole('textbox', { name: '0/' }).click(); + await bPage.getByRole('textbox', { name: '0/' }).fill(group.name); + await page.waitForTimeout(1000); await bPage.getByRole('button', { name: 'Uncategorised' }).click(); await page.waitForTimeout(1000); @@ -49,8 +54,9 @@ test('Delegation-Poll', async ({ page }) => { await gotoGroup(page, group); await page.getByRole('button', { name: 'Edit Group' }).dispatchEvent('click'); //Give b voting rights - // await createPermission(page, group, [2]); - // await assignPermission(page, group, "Test Permission", "bb"); + const permission_name = "Test Permission" + randomString(); + await createPermission(page, group, [2], permission_name); + await assignPermission(page, group, permission_name, process.env.SECONDUSER_NAME); await gotoGroup(page, group); diff --git a/Group.test.ts b/Group.test.ts index 8607bae..c37bf0e 100644 --- a/Group.test.ts +++ b/Group.test.ts @@ -1,11 +1,19 @@ import { test, expect } from '@playwright/test'; -import { login, newWindow } from './generic'; -import { createGroup, deleteGroup, gotoGroup, joinGroup } from './group'; +import { idfy, login, newWindow, randomString } from './generic'; +import { createGroup, deleteGroup, gotoFirstGroup, gotoGroup, joinGroup } from './group'; import { createPermission } from './permission'; +// TODO: Add test for this situation: +// User a creates a group which is invite only +// User b asks to join +// User a accepts b's request to join +// User b leaves the group +// User b asks to join again +// User a tries to reject, but it says error 400, "User already joined" test.describe('Group-Integration-Tests', () => { - const group = { name: "Test Group Group-Testing Public", public: true, invite: false } + test.describe.configure({ mode: 'serial' }); + const group = { name: "Test Group Group-Testing Public" + randomString(), public: true, invite: false } test('Create Group', async ({ page }) => { await login(page) @@ -18,12 +26,12 @@ test.describe('Group-Integration-Tests', () => { }) test('Join Group', async ({ page }) => { - await login(page, { email: "b@b.se", password: "b" }) + await login(page, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS, }) await joinGroup(page, group) }) test('Leave Group', async ({ page }) => { - await login(page, { email: "b@b.se", password: "b" }) + await login(page, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS, }) await gotoGroup(page, group) await page.getByRole('button', { name: 'Leave group' }).click(); await page.getByRole('button', { name: 'Yes', exact: true }).click(); @@ -37,7 +45,8 @@ test.describe('Group-Integration-Tests', () => { }); test.describe('Create-Delete-Group Invite only', () => { - const groupInvite = { name: "Test Group Group-Testing Invite only", public: true, invite: true } + test.describe.configure({ mode: 'serial' }); + const groupInvite = { name: "Test Group Group-Testing Invite only" + randomString(), public: true, invite: true } test('Create Group Invite', async ({ page }) => { await login(page) @@ -52,7 +61,7 @@ test.describe('Create-Delete-Group Invite only', () => { test('Ask to Join Group Invite', async ({ page }) => { await login(page) const bPage = await newWindow() - await login(bPage, { email: "b@b.se", password: "b" }) + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: "b" }) await joinGroup(bPage, groupInvite) await gotoGroup(page, groupInvite) @@ -64,7 +73,7 @@ test.describe('Create-Delete-Group Invite only', () => { test('Leave Group Invite', async ({ page }) => { const bPage = await newWindow() - await login(bPage, { email: "b@b.se", password: "b" }) + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: "b" }) await gotoGroup(bPage, groupInvite) await bPage.getByRole('button', { name: 'Leave group' }).click(); await bPage.getByRole('button', { name: 'Yes', exact: true }).click(); @@ -77,11 +86,37 @@ test.describe('Create-Delete-Group Invite only', () => { }) }); +test('Group-Invite', async ({ page }) => { + const group = { name: "Invitation " + randomString() } + await login(page); + await createGroup(page, group) + await page.getByRole('button', { name: 'Members', exact: true }).click(); + await page.getByRole('button', { name: 'avatar + Invite user' }).click(); + await page.getByRole('textbox', { name: 'User to invite' }).click(); + await page.getByRole('textbox', { name: 'User to invite' }).fill(process.env.SECONDUSER_NAME); + await page.getByRole('listitem').getByRole('button').filter({ hasText: /^$/ }).click(); + await expect(page.getByText('Successfully sent invite')).toBeVisible(); + + const bPage = await newWindow(); + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS }) + await bPage.getByText(`You have been invited to ${group.name} Accept Reject`).getByText('Reject').click(); + + await page.getByRole('textbox', { name: 'User to invite' }).click(); + await page.getByRole('textbox', { name: 'User to invite' }).fill(process.env.SECONDUSER_NAME); + + await page.getByRole('listitem').getByRole('button').filter({ hasText: /^$/ }).click(); + await expect(page.getByText('Successfully sent invite')).toBeVisible(); + + await bPage.reload(); + await bPage.getByText(`You have been invited to ${group.name} Accept Reject`).getByText('Accept').click(); + + await gotoGroup(bPage, group); +}) + test('Create-Delete-Group', async ({ page }) => { await login(page); - const rand = Math.random().toString(36).slice(2, 10); - const group = { name: 'Test Group Group-Test-' + rand, public: false }; + const group = { name: 'Test Group Group-Test-' + randomString(), public: false }; await createGroup(page, group); // Attempting to leave group as owner @@ -93,14 +128,14 @@ test('Create-Delete-Group', async ({ page }) => { // Workgroup testing await page.getByRole('button', { name: 'Work Groups' }).click(); await page.getByRole('button', { name: '+ Add Workgroup' }).click(); - await page.getByLabel('Name * 0/').click(); - await page.getByLabel('Name * 0/').fill('Test Workgroup directjoin'); + await page.getByLabel('Name').click(); + await page.getByLabel('Name').fill('Test Workgroup directjoin'); await page.getByRole('button', { name: 'Create', exact: true }).click(); await page.getByRole('button', { name: 'Join', exact: true }).click(); await page.getByRole('button', { name: '+ Add Workgroup' }).click(); await page.getByLabel('No').check(); - await page.getByLabel('Name * 0/').click(); - await page.getByLabel('Name * 0/').fill('Test group invite only'); + await page.getByLabel('Name').click(); + await page.getByLabel('Name').fill('Test group invite only'); await page.getByRole('button', { name: 'Create', exact: true }).click(); await page.getByRole('button', { name: 'Ask to join' }).click(); await expect(page.getByText('Pending')).toBeVisible(); @@ -127,12 +162,12 @@ test('Create-Delete-Group', async ({ page }) => { await page.getByRole('button', { name: 'Delete', exact: true }).nth(1).click(); // Create, deactive and delete area await page.getByRole('button', { name: 'Areas' }).click(); - await page.getByLabel('Tag * 0/').click(); - await page.getByLabel('Tag * 0/').fill('Test Tag'); - await page.getByLabel('Description 0/').click(); - await page.getByLabel('Description 0/').fill('Test tag description'); + await page.getByLabel('Tag').click(); + await page.getByLabel('Tag').fill('Test Tag'); + await page.getByLabel('Description').click(); + await page.getByLabel('Description').fill('Test tag description'); await page.getByRole('button', { name: 'Add' }).click(); - await expect(page.locator('div:nth-child(3) > div').first()).toHaveText('Test Tag'); + await expect(page.locator(`#test-tag`).first()).toHaveText('Test Tag'); await page.locator('.slider').first().click(); await page.locator('.text-red-500').first().click(); await page.getByRole('button', { name: 'No', exact: true }).click(); diff --git a/Imac.test.ts b/Imac.test.ts index 5ce9d9d..707f549 100644 --- a/Imac.test.ts +++ b/Imac.test.ts @@ -1,11 +1,11 @@ import test, { expect } from "@playwright/test"; import { login, newWindow, randomString } from "./generic"; import { createArea, createGroup, gotoGroup, joinGroup } from "./group"; -import { areaVote, createPoll, createProposal, fastForward, goToPost, predictionProbability, predictionStatementCreate } from "./poll"; +import { areaVote, createPoll, createProposal, fastForward, goToPost, predictionProbability, predictionStatementCreate, vote } from "./poll"; import { assignPermission, createPermission } from "./permission"; test('Imac-Test', async ({ page }) => { - test.setTimeout(90000); + test.setTimeout(95000); await login(page); @@ -25,7 +25,7 @@ test('Imac-Test', async ({ page }) => { await fastForward(page, 1); - const proposal = { title: "Test 1" } + const proposal = { title: "Test 1", vote: 2 } await createProposal(page, proposal); await fastForward(page, 1); @@ -36,7 +36,11 @@ test('Imac-Test', async ({ page }) => { await predictionProbability(page, proposal); - await fastForward(page, 3); + await fastForward(page, 2); + + await vote(page, proposal); + + await fastForward(page, 1); // //TODO Make the test shorter. There's a way to do this in pollCreate with all of the phase times being identical. await page.waitForTimeout(70000); @@ -48,7 +52,7 @@ test('Imac-Test', async ({ page }) => { await page.waitForTimeout(5000); await page.reload(); - expect(page.locator('#poll-tag-imac').getByText("20%")).toBeVisible(); + await expect(page.locator('#poll-tag-imac').getByText("20%")).toBeVisible(); // await page.locator('.text-center.dark\\:saturate-\\[60\\%\\].transition-colors.duration-50.w-12.px-4.py-1.ml-2').nth(1).click(); // await expect(page.getByText('Successfully evaluated')).toBeVisible(); @@ -70,7 +74,7 @@ test('Imac-Test-2-Users', async ({ page }) => { const bPage = await newWindow(); - await login(bPage, { email: "b@b.se", password: "b" }) + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: "b" }) await joinGroup(bPage, group) const permission_name = "Consequence voting " + randomString() diff --git a/Kanban.test.ts b/Kanban.test.ts index f694672..db8e274 100644 --- a/Kanban.test.ts +++ b/Kanban.test.ts @@ -1,135 +1,141 @@ -import { test, expect } from '@playwright/test'; -import { login, randomString } from './generic'; -import { createGroup, gotoGroup } from './group'; +import { test, expect } from "@playwright/test"; +import { login, randomString } from "./generic"; +import { createGroup, gotoGroup } from "./group"; -test('Kanban-User', async ({ page }) => { +test("Kanban-User", async ({ page }) => { await login(page); // Navigate to the kanban page - await page.goto('/kanban'); - await expect(page).toHaveURL('/kanban'); + await page.goto(`${process.env.LINK}/kanban`); + await expect(page).toHaveURL(`${process.env.LINK}/kanban`); // Check if the kanban board is visible - const kanbanBoard = await page.locator('#kanban-board'); + const kanbanBoard = await page.locator("#kanban-board"); await expect(kanbanBoard).toBeVisible(); - const doneButton = await page.locator('#Done-add'); + const doneButton = await page.locator("#Done-add"); await expect(doneButton).toBeVisible(); await page.waitForTimeout(400); await doneButton.click(); - const createModal = await page.locator('#create-kanban-entry-modal'); + const createModal = await page.locator("#create-kanban-entry-modal"); await expect(createModal).toBeVisible(); - await page.locator('#create-kanban-text').fill('test kanban'); - await page.locator('#create-kanban-textarea').fill('test kanban description'); + await page.locator("#create-kanban-text").fill("test kanban"); + await page.locator("#create-kanban-textarea").fill("test kanban description"); - await page.locator('button', { hasText: "Confirm" }).click() + await page.locator("button", { hasText: "Confirm" }).click(); await expect(createModal).toBeHidden(); }); -test('Kanban-Group', async ({ page }) => { +test("Kanban-Group", async ({ page }) => { await login(page); // await gotoGroup(page); - await createGroup(page, { name: "Test Kanban Group " + randomString(), public: true, invite: false }) + await createGroup(page, { + name: "Test Kanban Group " + randomString(), + public: true, + invite: false, + }); - await page.locator('#group-tasks-sidebar-button').click(); + await page.locator("#group-tasks-sidebar-button").click(); - // await expect(page).toHaveURL('/kanban?groupId='); + // await expect(page).toHaveURL(`${process.env.LINK}/kanban?groupId=`); // Check if the kanban board is visible - const kanbanBoard = await page.locator('#kanban-board'); + const kanbanBoard = await page.locator("#kanban-board"); await expect(kanbanBoard).toBeVisible(); - const doneButton = await page.locator('#Done-add'); + const doneButton = await page.locator("#Done-add"); await expect(doneButton).toBeVisible(); doneButton.click(); - const createModal = await page.locator('#create-kanban-entry-modal'); + const createModal = await page.locator("#create-kanban-entry-modal"); await expect(createModal).toBeVisible(); - await page.locator('#create-kanban-text').fill('test kanban'); - await page.locator('#create-kanban-textarea').fill('test kanban description'); + await page.locator("#create-kanban-text").fill("test kanban"); + await page.locator("#create-kanban-textarea").fill("test kanban description"); - await page.locator('button', { hasText: "Confirm" }).click() + await page.locator("button", { hasText: "Confirm" }).click(); await expect(createModal).toBeHidden(); }); - -test('Kanban-Edit', async ({ page }) => { +test("Kanban-Edit", async ({ page }) => { await login(page); // Navigate to the kanban page - await page.goto('/kanban'); - await expect(page).toHaveURL('/kanban'); + await page.goto(`${process.env.LINK}/kanban`); + await expect(page).toHaveURL(`${process.env.LINK}/kanban`); // Check if the kanban board is visible - const kanbanBoard = await page.locator('#kanban-board'); + const kanbanBoard = await page.locator("#kanban-board"); await expect(kanbanBoard).toBeVisible(); //n-th member of done-kanban-lane - const doneLane = await page.locator('#Done-kanban-lane'); + const doneLane = await page.locator("#Done-kanban-lane"); await page.waitForTimeout(1000); - const kanbanEntry = page.locator('#Done-kanban-lane > ul > div').first(); + const kanbanEntry = page.locator("#Done-kanban-lane > ul > div").first(); await expect(kanbanEntry).toBeVisible(); await kanbanEntry.click(); await page.waitForTimeout(300); - const kanbanEntryModal = await page.locator('#kanban-entry-modal'); + const kanbanEntryModal = await page.locator("#kanban-entry-modal"); await expect(kanbanEntryModal).toBeVisible(); - const editButton = await page.locator('#Edit'); + const editButton = await page.locator("#Edit"); editButton.click(); await page.waitForTimeout(300); - await page.locator('#kanban-edit-title').fill('test kanban edited'); - await page.locator('#kanban-edit-description').fill('test kanban description edited'); + await page.locator("#kanban-edit-title").fill("test kanban edited"); + await page + .locator("#kanban-edit-description") + .fill("test kanban description edited"); // Add response listener before clicking update - const responsePromise = page.waitForResponse(response => - response.url().includes('/user/kanban/entry/update') && response.status() === 200 + const responsePromise = page.waitForResponse( + (response) => + response.url().includes("/user/kanban/entry/update") && + response.status() === 200 ); - await page.click('#Update'); + await page.click("#Update"); await responsePromise; // Wait for successful response - await page.click('#Close'); + await page.click("#Close"); await expect(kanbanEntryModal).toBeHidden(); }); -test('Kanban-Delete', async ({ page }) => { +test("Kanban-Delete", async ({ page }) => { await login(page); - // Navigate to the kanban page - await page.goto('/kanban'); - await expect(page).toHaveURL('/kanban'); + await page.goto(`${process.env.LINK}/kanban`); + await expect(page).toHaveURL(`${process.env.LINK}/kanban`); // Check if the kanban board is visible - const kanbanBoard = await page.locator('#kanban-board'); + const kanbanBoard = await page.locator("#kanban-board"); await expect(kanbanBoard).toBeVisible(); //n-th member of done-kanban-lane - const doneLane = await page.locator('#Done-kanban-lane'); + const doneLane = await page.locator("#Done-kanban-lane"); await page.waitForTimeout(1000); - const kanbanEntry = page.locator('#Done-kanban-lane > ul > div').first(); + const kanbanEntry = page.locator("#Done-kanban-lane > ul > div").first(); await expect(kanbanEntry).toBeVisible(); await kanbanEntry.click(); await page.waitForTimeout(300); - const editButton = await page.locator('#Edit'); + const editButton = await page.locator("#Edit"); editButton.click(); - const kanbanEntryModal = await page.locator('#kanban-entry-modal'); + const kanbanEntryModal = await page.locator("#kanban-entry-modal"); await expect(kanbanEntryModal).toBeVisible(); - const deleteButton = await page.locator('#Delete'); + const deleteButton = await page.locator("#Delete"); await expect(deleteButton).toBeVisible(); await deleteButton.click(); await expect(kanbanEntryModal).toBeHidden(); -}); \ No newline at end of file +}); diff --git a/Notification.test.ts b/Notification.test.ts new file mode 100644 index 0000000..8903935 --- /dev/null +++ b/Notification.test.ts @@ -0,0 +1,91 @@ +import { test, chromium, expect } from '@playwright/test'; +import { login, newWindow, randomString } from "./generic"; +import { createGroup, gotoGroup, joinGroup } from './group'; +import { createPoll, fastForward, results } from './poll'; +import { Group, Poll } from './types'; +import { env } from 'process'; + +test('Group-Notification', async ({ page }) => { + + const group: Group = { name: "GroupTesting" + randomString(), public: true } + await login(page); + await createGroup(page, group); + + const bPage = await newWindow(); + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS }); + + await joinGroup(bPage, group); + await gotoGroup(bPage, group); + await bPage.locator('#group-header').getByRole('button').filter({ hasText: /^$/ }).click(); + await bPage.getByRole('button', { name: 'Group', exact: true }).click(); + await bPage.getByRole('button', { name: 'Group User', exact: true }).click(); + await bPage.getByRole('button', { name: 'Kanban', exact: true }).click(); + await bPage.getByRole('button', { name: 'Polls', exact: true }).click(); + await bPage.getByRole('button', { name: 'Events', exact: true }).click(); + await bPage.getByRole('button', { name: 'Threads', exact: true }).click(); + + const poll: Poll = { title: "NotificationPoll" + randomString() } + await createPoll(page, poll); + + await bPage.reload(); + + // TOOD: Once notification system is done, set an expect here to get the right message and that the notification link leads to the right poll + + await page.locator('#notifications-list').click(); + await expect(page.getByRole('button', { name: 'A new poll has been posted' }).nth(1)).toBeVisible(); + + await bPage.locator('#notifications-list').click(); + await expect(bPage.getByRole('button', { name: 'A new poll has been posted' }).nth(1)).toBeVisible(); +}) + + +test('Poll-Start-To-Finish', async ({ page }) => { + await login(page); + + const bPage = await newWindow() + await login(bPage, { email: env.SECONDUSER_MAIL, password: env.SECONDUSER_PASS }) + + const group = { name: 'Test Poll start to finish notifications' + randomString(), public: true }; + await createGroup(page, group); + + await gotoGroup(page, group); + await joinGroup(bPage, group); + await gotoGroup(bPage, group) + + await bPage.locator('#group-header').getByRole('button').filter({ hasText: /^$/ }).click(); + await bPage.getByRole('button', { name: 'Subscribe to All', exact: true }).click(); + + const poll = { title: 'title' + randomString(), phase_time: 1 } + await createPoll(page, poll); + + await bPage.reload() + await bPage.locator('#notifications-list').click(); + await bPage.getByRole('button', { name: 'a new poll has been posted' }).nth(0).click(); + await expect(bPage.getByText(poll.title)).toBeVisible() + + await bPage.getByRole('button').filter({ hasText: /^$/ }).nth(4).click(); + await bPage.getByRole('button', { name: 'Subscribe to All' }).click(); + + await comment(page, "Notify about me please"); + + await bPage.reload() + await bPage.locator('#notifications-list').click(); + await bPage.getByRole('button', { name: 'a new comment has been posted' }).nth(0).click(); + await expect(bPage.getByText(poll.title)).toBeVisible() + + await fastForward(page, 6); + + await expect(page.getByText('Results There is no winning')).toBeVisible(); + + //TODO second comment and poll ff notifications, maybe also evaluation. + + await comment(page, "Notify about me please") +}); + +const comment = async (page, message: string) => { + await page.getByPlaceholder('Write a comment...').click(); + await page.getByPlaceholder('Write a comment...').fill(message); + await page.locator('.text-center.dark\\:saturate-\\[60\\%\\].transition-colors.duration-50.submit-button').click(); + + +} diff --git a/Permissions.test.ts b/Permissions.test.ts index c2af423..2a0b1a7 100644 --- a/Permissions.test.ts +++ b/Permissions.test.ts @@ -1,7 +1,8 @@ import test, { expect } from "@playwright/test"; import { createGroup, deleteGroup, gotoGroup, joinGroup } from "./group"; -import { login, newWindow } from "./generic"; +import { login, newWindow, randomString } from "./generic"; import { assignPermission, createPermission } from "./permission"; +import 'dotenv/config' test('Create-Permission-Full', async ({ page }) => { await login(page); @@ -13,15 +14,22 @@ test('Create-Permission-Full', async ({ page }) => { await expect(page.locator('#group-header-title')).toHaveText(group.name); await page.getByRole('button', { name: 'Edit Group' }).dispatchEvent('click'); - await createPermission(page, group, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + const permission_name = "No Permissions" + + let perms = [] + for (let i = 0; i < 17; i++) { + perms.push(i) + } + + await createPermission(page, group, perms, permission_name); const bPage = await newWindow(); - await login(bPage, { email: 'b@b.se', password: 'b' }); + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS }); await joinGroup(bPage, group); await page.waitForTimeout(400); - await assignPermission(page, group); + await assignPermission(page, group, permission_name, process.env.SECONDUSER_NAME); await page.waitForTimeout(300); @@ -38,23 +46,23 @@ test('Create-Permission-Full', async ({ page }) => { test('Create-Permission-None', async ({ page }) => { await login(page); - const rand = Math.random().toString(36).slice(2, 10); - const group = { name: 'Test Group Permissions ' + rand, public: true }; + const group = { name: 'Test Group Permissions ' + randomString(), public: true }; await createGroup(page, group); await expect(page.locator('#group-header-title')).toHaveText(group.name); const bPage = await newWindow(); - await login(bPage, { email: 'b@b.se', password: 'b' }); + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS }); await joinGroup(bPage, group); await page.getByRole('button', { name: 'Edit Group' }).dispatchEvent('click') - await createPermission(page, group, []); + const permission_name = "No Permissions" + await createPermission(page, group, [], permission_name); await page.waitForTimeout(1000); - await assignPermission(page, group) + await assignPermission(page, group, permission_name, process.env.SECONDUSER_NAME) await page.waitForTimeout(500); await gotoGroup(bPage, group); diff --git a/Poll.test.ts b/Poll.test.ts index 9cf2cb8..4edae5b 100644 --- a/Poll.test.ts +++ b/Poll.test.ts @@ -12,8 +12,11 @@ import { } from './poll'; import { login, newWindow, randomString, idfy } from './generic'; import { gotoGroup, createArea, createGroup, joinGroup } from './group'; +import { idfy } from './generic'; +import 'dotenv/config' test.describe('Basic-Post-Integration-Tests', () => { + test.describe.configure({ mode: 'serial' }) const group = { name: 'Test Group Poll' + randomString(), public: false }; const poll = { title: 'Test Poll Create and Go ' + randomString(), date: false }; @@ -89,6 +92,18 @@ test('Proposal-Test', async ({ page }) => { await fastForward(page, 1); await createProposal(page, { title: 'Lol', description: 'Description funny' }); + + // Testing comment tagging and filtering system + // TODO: Expand this test + await page.getByPlaceholder('Write a comment...').click(); + await page.getByPlaceholder('Write a comment...').fill('#'); + await page.getByRole('button', { name: 'Lol' }).click(); + await page.locator('.text-center.dark\\:saturate-\\[60\\%\\].transition-colors.duration-50.submit-button').click(); + await page.getByRole('button', { name: 'Filter by Proposal' }).click(); + await page.getByRole('checkbox').check(); + await page.getByRole('button', { name: 'Close modal', exact: true }).click(); + await expect(page.getByText('#Lol')).toBeVisible(); + }); test('Proposal-Spam-Test', async ({ page }) => { @@ -283,7 +298,7 @@ test('Prediction-Probabilities', async ({ page }) => { const bPage = await newWindow(); - await login(bPage, { email: 'b@b.se', password: 'b' }); + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS }); await joinGroup(bPage, group); @@ -339,7 +354,7 @@ test('Prediction-Probabilities-2', async ({ page }) => { const bPage = await newWindow(); - await login(bPage, { email: 'b@b.se', password: 'b' }); + await login(bPage, { email: process.env.SECONDUSER_MAIL, password: process.env.SECONDUSER_PASS }); await joinGroup(bPage, group); diff --git a/Schedule.test.ts b/Schedule.test.ts index d444f11..4d03506 100644 --- a/Schedule.test.ts +++ b/Schedule.test.ts @@ -4,7 +4,7 @@ import { login } from './generic'; test('Create-Delete-Schedule-Event', async ({ page }) => { await login(page); - await page.getByRole('link', { name: 'Schedule' }).click(); + await page.getByRole('button', { name: 'Schedule' }).click(); await page.getByRole('button', { name: '15' }).dblclick(); await page.getByLabel('Title').fill('Event at 15:th'); await page.getByLabel('Description').fill('This is a test event at 15:th'); @@ -31,8 +31,6 @@ test('Create-Delete-Schedule-Event', async ({ page }) => { await page.getByLabel('End Date').press('Shift+Tab'); await page.getByLabel('End Date').fill('2027-08-16T00:01'); await page.getByRole('button', { name: 'Update', exact: true }).click(); - await page.getByRole('button', { name: 'Cancel', exact: true }).click(); - await page.getByRole('button', { name: 'Delete', exact: true }).click(); await expect(page.getByText('Event deleted')).toBeVisible(); await expect(page.getByText('Failed to update event')).toBeHidden(); diff --git a/Thread.test.ts b/Thread.test.ts index 601d6ae..5dd3768 100644 --- a/Thread.test.ts +++ b/Thread.test.ts @@ -59,6 +59,8 @@ test('Thread-Create-Report-Delete', async ({ page }) => { await page.locator('.submit-button').nth(1).click(); //TODO Test images in comment + + await page.locator('#multiple-choices').getByRole('button').click(); await page.getByRole('button', { name: 'Report Thread' }).click(); await page.getByRole('textbox', { name: 'Title' }).click(); await page.getByRole('textbox', { name: 'Title' }).fill('Report Test'); diff --git a/User.test.ts b/User.test.ts index 97bb6ce..1bada03 100644 --- a/User.test.ts +++ b/User.test.ts @@ -5,8 +5,6 @@ test('Edit User', async ({ page }) => { await login(page); await page.getByRole('button', { name: 'default pfp' }).click(); await page.getByRole('button', { name: 'User Profile', exact: true }).click(); - await page.getByRole('button').nth(3).click(); - await page.getByRole('button', { name: 'default pfp' }).click(); await expect(page.getByText('Contact Information')).toBeVisible(); await page.locator("#edit-profile-button").click(); await page.getByLabel('Name').fill('a edited'); diff --git a/delegation.ts b/delegation.ts index c03f437..dbd3a56 100644 --- a/delegation.ts +++ b/delegation.ts @@ -1,9 +1,11 @@ import { expect } from "@playwright/test"; export async function becomeDelegate(page: any, group = { name: 'Test Group Delegation' }) { - await page.getByRole('link', { name: 'Delegations' }).click(); + await page.getByRole('button', { name: 'Delegations' }).first().click(); - await page.locator('#delegate-group-select').selectOption({ label: group.name }); + // await page.locator('#delegate-group-select').selectOption({ label: group.name }); + await page.getByRole('textbox', { name: '0/' }).click(); + await page.getByRole('textbox', { name: '0/' }).fill(group.name); await page.waitForTimeout(1000); await expect(page.getByRole('button', { name: 'Become delegate' })).toBeVisible(); await page.waitForTimeout(1000); diff --git a/forward-facing-niko-oneshot-isnt-real-it-cant-hurt-you-v0-3ggf23q4ijcf1.webp b/forward-facing-niko-oneshot-isnt-real-it-cant-hurt-you-v0-3ggf23q4ijcf1.webp deleted file mode 100644 index b6a4b1a..0000000 Binary files a/forward-facing-niko-oneshot-isnt-real-it-cant-hurt-you-v0-3ggf23q4ijcf1.webp and /dev/null differ diff --git a/generic.ts b/generic.ts index 1a2235c..cef4e7f 100644 --- a/generic.ts +++ b/generic.ts @@ -1,4 +1,9 @@ import { chromium, expect } from '@playwright/test'; +import 'dotenv/config' + +export const idfy = (text: string) => { + return text.trim().replace(/\s+/g, '-').toLowerCase(); +} export async function newWindow() { const browser = await chromium.launch(); @@ -8,10 +13,10 @@ export async function newWindow() { } export async function login(page: any, { - email = process.env.E2E_EMAIL ?? 'a@a.se', - password = process.env.E2E_PASSWORD ?? 'a', + email = process.env.MAINUSER_MAIL ?? 'a@a.se', + password = process.env.MAINUSER_PASS ?? 'a', } = {}) { - await page.goto('/login'); + await page.goto(`${process.env.LINK}/login`); await expect(page.locator('#login-page')).toBeVisible(); await page.waitForTimeout(700); @@ -19,36 +24,35 @@ export async function login(page: any, { await page.fill('input[name="password"]', password); await page.click('button[type="submit"]'); - await expect(page).toHaveURL('/home'); - - if (await page.getByRole('button', { name: 'Ok' }).isVisible()) { - await page.getByRole('button', { name: 'Ok' }).click(); + await expect(page).toHaveURL(`${process.env.LINK}/home`); + if (await page.getByRole('button', { name: 'Ok', exact: true }).isVisible()) { + await page.getByRole('button', { name: 'Ok', exact: true }).click(); } } export async function loginEnter(page: any, { - email = process.env.E2E_EMAIL ?? 'a@a.se', - password = process.env.E2E_PASSWORD ?? 'a', + email = process.env.MAINUSER_MAIL ?? 'a@a.se', + password = process.env.MAINUSER_PASS ?? 'a', } = {}) { - await page.goto('/login'); + await page.goto(`${process.env.LINK}/login`); await expect(page.locator('#login-page')).toBeVisible(); await page.waitForTimeout(700); await page.fill('input[name="email"]', email); await page.fill('input[name="password"]', password); - await page.getByLabel('Password * 1/').press('Enter'); + await page.getByLabel('Password').press('Enter'); - await expect(page).toHaveURL('/home'); + await expect(page).toHaveURL(`${process.env.LINK}/home`); } // Tests registring a user // Only works if PUBLIC_EMAIL_REGISTRATION=FALSE in .env in the flowback-backend repository // TODO: Automated Email testing export async function register(page: any) { - const randomUSername = randomString(); - const randomEmail = `${randomUSername}@flowback.test`; + const randomUsername = randomString(); + const randomEmail = `${randomUsername}@flowback.test`; - await page.goto('/login'); + await page.goto(`${process.env.LINK}/login`); await expect(page.locator('#login-page')).toBeVisible(); await page.waitForTimeout(500); @@ -77,7 +81,7 @@ export async function register(page: any) { await page.getByLabel('Verification Code').click(); await page.getByLabel('Verification Code').fill('geageageadgea'); await page.getByLabel('Username').click(); - await page.getByLabel('Username').fill(randomUSername); + await page.getByLabel('Username').fill(randomUsername); await page.getByLabel('Choose a Password').click(); await page.getByLabel('Choose a Password').fill('SecretPassword123123!'); await page.getByRole('button', { name: 'Send' }).click(); @@ -89,11 +93,13 @@ export async function register(page: any) { await page.getByRole('button', { name: 'Send' }).click(); await expect(page.getByText('Success')).toBeVisible(); - await expect(page).toHaveURL('/home'); + await expect(page).toHaveURL(`${process.env.LINK}/home`); if (await page.getByRole('button', { name: 'Ok' }).isVisible()) { await page.getByRole('button', { name: 'Ok' }).click(); } + + return { username: randomUsername, email: randomEmail, password: 'SecretPassword123123!' }; } export async function logout(page: any) { diff --git a/group.ts b/group.ts index 5adf577..6526d86 100644 --- a/group.ts +++ b/group.ts @@ -1,5 +1,6 @@ import { idfy } from './generic'; import { expect } from "@playwright/test"; +import { idfy } from './generic'; export type group = { name: string, @@ -21,16 +22,16 @@ export async function createGroup(page: any, group: group = { name: 'Test Group' await button.click(); } else { - await page.getByRole('link', { name: 'Groups' }).click(); + await page.getByRole('button', { name: 'Groups' }).click(); await page.getByRole('button', { name: 'Create Group' }).click(); - await page.getByLabel('Title * 0/').click(); - await page.getByLabel('Title * 0/').fill(group.name); - await page.getByLabel('Description 0/').click(); - await page.getByLabel('Description 0/').fill('Test Group Description'); - await page.locator(".image-upload > input").nth(0).setInputFiles('./tests/forward-facing-niko-oneshot-isnt-real-it-cant-hurt-you-v0-3ggf23q4ijcf1.webp'); + await page.getByLabel('Title').click(); + await page.getByLabel('Title').fill(group.name); + await page.getByLabel('Description').click(); + await page.getByLabel('Description').fill('Test Group Description'); + await page.locator(".image-upload > input").nth(0).setInputFiles('./image.png'); await page.getByRole('button', { name: 'Confirm' }).click(); await page.waitForTimeout(500); - await page.locator(".image-upload > input").nth(1).setInputFiles('./tests/forward-facing-niko-oneshot-isnt-real-it-cant-hurt-you-v0-3ggf23q4ijcf1.webp'); + await page.locator(".image-upload > input").nth(1).setInputFiles('./image.png'); await page.locator("#cropper-confirm").first().click(); await page.locator('fieldset').filter({ hasText: 'Public? Yes No' }).getByLabel(group.public ? 'Yes' : 'No').check(); if (group.public) @@ -57,7 +58,7 @@ export async function gotoGroup(page: any, group = { name: 'Test Group' }) { export async function gotoFirstGroup(page: any) { await page.locator("#groups").click(); - await page.locator("#groups-list > div").first().click(); + await page.locator("#groups-list > button").nth(1).click(); } export async function joinGroup(page: any, group = { name: 'Test Group' }) { @@ -66,7 +67,8 @@ export async function joinGroup(page: any, group = { name: 'Test Group' }) { await page.getByPlaceholder('Search groups').fill(group.name); await page.getByRole('heading', { name: group.name, exact: true }); const joinButton = await page.locator(`#join-${idfy(group.name)}`).first(); - console.log(`#join-${idfy(group.name)}`); + // console.log(`#join-${idfy(group.name)}`); + await expect(joinButton).toBeVisible() // await expect(joinButton).toBeVisible(); @@ -81,17 +83,17 @@ export async function deleteGroup(page: any, group = { name: 'Test Group', publi await page.getByRole('button', { name: 'Cancel', exact: true }).click(); await page.getByRole('button', { name: 'Delete Group' }).click(); await page.getByRole('button', { name: 'Yes', exact: true }).click(); - await expect(page).toHaveURL('/groups'); + await expect(page).toHaveURL(`${process.env.LINK}/groups`); } export async function createArea(page: any, group = { name: 'Test Group', public: false }, tag = "Test Tag") { await page.getByRole('button', { name: 'Edit Group' }).dispatchEvent('click') await expect(page.getByRole('button', { name: 'Areas' })).toBeVisible(); await page.getByRole('button', { name: 'Areas' }).click(); - await page.getByLabel('Tag * 0/').click(); - await page.getByLabel('Tag * 0/').fill(tag); - await page.getByLabel('Description 0/').click(); - await page.getByLabel('Description 0/').fill('Tag description'); + await page.getByLabel('Tag').click(); + await page.getByLabel('Tag').fill(tag); + await page.getByLabel('Description').click(); + await page.getByLabel('Description').fill('Tag description'); await page.getByRole('button', { name: 'Add' }).click(); await expect(page.locator('div:nth-child(3) > div').filter({ hasText: tag })).toHaveText(tag); } \ No newline at end of file diff --git a/image.png b/image.png new file mode 100644 index 0000000..6a8fb00 Binary files /dev/null and b/image.png differ diff --git a/permission.ts b/permission.ts index ac752dd..3c67e7c 100644 --- a/permission.ts +++ b/permission.ts @@ -32,9 +32,14 @@ export async function assignPermission(page: any, group = { name: 'Test Group', await page.getByRole('button', { name: 'Permissions' }).click(); await page.getByRole('button', { name: 'Assign' }).click(); - await page.locator(`#plus-${user_name}`).click() - await page.getByRole('listitem').locator(`id=permission-${idfy(permission_name)}`).nth(1).click(); + // console.log(`#plus-${idfy(user_name)}`); + + const addRoleButton = page.locator(`#plus-${idfy(user_name)}`) + await expect(addRoleButton).toBeVisible(); + await addRoleButton.click(); + + await page.getByRole('listitem').locator(`#permission-${idfy(permission_name)}-${idfy(user_name)}`).click(); await expect(page.getByText('Successfully updated permission')).toBeVisible(); } \ No newline at end of file diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..069f90e --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,79 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// import path from 'path'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './.', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('')`. */ + // baseURL: 'http://localhost:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://localhost:3000', + // reuseExistingServer: !process.env.CI, + // }, +}); diff --git a/poll.ts b/poll.ts index f276116..9dd2690 100644 --- a/poll.ts +++ b/poll.ts @@ -1,5 +1,7 @@ import { idfy } from './generic'; import { expect } from '@playwright/test'; +import { idfy } from './generic'; + // Only works inside a poll export async function fastForward(page: any, times = 1) { @@ -21,9 +23,9 @@ export async function createPoll(page: any, { await page.getByRole('button', { name: 'Create a post' }).click(); await page.waitForTimeout(300); expect(await page.getByText('PollThread')).toBeVisible(); - await page.getByLabel('Title * 0/').click(); - await page.getByLabel('Title * 0/').fill(title); - await page.getByLabel('Description 0/').fill('Test Description'); + await page.getByLabel('Title').click(); + await page.getByLabel('Title').fill(title); + await page.getByLabel('Description').fill('Test Description'); if (date) await page.getByLabel('Date Poll').check(); @@ -34,8 +36,8 @@ export async function createPoll(page: any, { await page.getByRole('spinbutton').fill(phase_time.toString()); await page.getByRole('button', { name: 'Post' }).click(); - await expect(page.getByText('Could not create Poll')).not.toBeVisible(); await expect(page.getByText('Poll Created')).toBeVisible(); + await expect(page.getByText('Could not create Poll')).not.toBeVisible(); await page.waitForTimeout(500); expect(await page.getByRole('heading', { name: title })).toBeVisible(); @@ -44,12 +46,12 @@ export async function createPoll(page: any, { export async function goToPost(page: any, { title = 'Test Poll' }) { - await page.getByRole('link', { name: 'Home' }).click(); + await page.getByRole('button', { name: 'Home' }).click(); await page.getByPlaceholder('Search polls').click(); await page.getByPlaceholder('Search polls').fill(title); - expect(await page.locator('#thumbnails > div').getByRole('link', { name: title, exact: true }).first()).toBeVisible(); + await expect(await page.locator('#thumbnails > div').getByRole('link', { name: title, exact: true }).first()).toBeVisible(); await page.locator('#thumbnails > div').getByRole('link', { name: title, exact: true }).first().click(); - expect(await page.getByRole('heading', { name: title })).toBeVisible(); + await expect(await page.getByRole('heading', { name: title })).toBeVisible(); // expect(await page.locator('#poll-thumbnail-140').getByRole('link', { name: 'Test Poll' })).toBeVisible(); } @@ -83,14 +85,14 @@ export async function createProposal(page: any, { await page.getByLabel('Description 0/').click(); await page.getByLabel('Description 0/').fill(description); await page.getByRole('button', { name: 'Confirm' }).click(); - expect(await page.getByText('Successfully added proposal').first()).toBeVisible(); + await expect(await page.getByText('Successfully added proposal').first()).toBeVisible(); } export async function predictionStatementCreate(page: any, proposal = { title: "Proposal Title" }, prediction = { title: "Prediction Title" }) { expect(await page.locator('#poll-timeline').filter({ hasText: 'Phase 3. Prediction statements creation' })) // if (await page.locator(`#${idfy(proposal.title)}-selection`).first().isVisible()) await page.waitForTimeout(200); - const visible = await page.getByText('To make a consequence, please').isVisible() + const visible = await page.getByText('To make a consequence').isVisible() if (visible) await page.locator(`#${idfy(proposal.title)}-selection`).first().click(); @@ -141,10 +143,10 @@ export async function vote(page: any, proposal = { title: "Proposal Title", vote export async function results(page: any) { expect(await page.locator('#poll-timeline').filter({ hasText: 'Current: Phase 7. Results and' })) - expect(await page.getByText('Results', { exact: true })).toBeVisible(); + await expect(await page.getByText('Results', { exact: true })).toBeVisible(); //TODO: no need for canvas when there have been 0 votes - expect(await page.locator('canvas')).toBeVisible(); + await expect(await page.locator('canvas')).toBeVisible(); await page.locator('canvas').click({ position: { diff --git a/test.bash b/test.bash new file mode 100644 index 0000000..50b766e --- /dev/null +++ b/test.bash @@ -0,0 +1 @@ +npx playwright test . --workers=2 --project=chromium --retries=2 diff --git a/tsconfig.json b/tsconfig.json index 5dd7590..1003d09 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,4 +10,4 @@ ] } -} \ No newline at end of file +} diff --git a/types.ts b/types.ts new file mode 100644 index 0000000..61c44b1 --- /dev/null +++ b/types.ts @@ -0,0 +1,11 @@ + + +export type Group = { + name: string; + public: boolean; +} + +export type Poll = { + title: string; + date?: boolean; +} \ No newline at end of file