// @watch start // templates/repo/issue/view_content/** // web_src/css/repo/issue-** // web_src/js/features/repo-issue** // @watch end /* eslint playwright/expect-expect: ["error", { "assertFunctionNames": ["check_wip"] }] */ import {expect, type Page} from '@playwright/test'; import {test, login_user, login} from './utils_e2e.ts'; test.beforeAll(async ({browser}, workerInfo) => { await login_user(browser, workerInfo, 'user2'); }); test.describe('Pull: Toggle WIP', () => { const prTitle = 'pull5'; async function toggle_wip_to({page}, should: boolean) { await page.waitForLoadState('domcontentloaded'); if (should) { await page.getByText('Still in progress?').click(); } else { await page.getByText('Ready for review?').click(); } } async function check_wip({page}, is: boolean) { const elemTitle = 'h1'; const stateLabel = '.issue-state-label'; await page.waitForLoadState('domcontentloaded'); await expect(page.locator(elemTitle)).toContainText(prTitle); await expect(page.locator(elemTitle)).toContainText('#5'); if (is) { await expect(page.locator(elemTitle)).toContainText('WIP'); await expect(page.locator(stateLabel)).toContainText('Draft'); } else { await expect(page.locator(elemTitle)).not.toContainText('WIP'); await expect(page.locator(stateLabel)).toContainText('Open'); } } test.beforeEach(async ({browser}, workerInfo) => { const page = await login({browser}, workerInfo); const response = await page.goto('/user2/repo1/pulls/5'); expect(response?.status()).toBe(200); // Status OK // ensure original title await page.locator('#issue-title-edit-show').click(); await page.locator('#issue-title-editor input').fill(prTitle); await page.getByText('Save').click(); await check_wip({page}, false); }); test('simple toggle', async ({browser}, workerInfo) => { test.skip(workerInfo.project.name === 'Mobile Safari', 'Unable to get tests working on Safari Mobile, see https://codeberg.org/forgejo/forgejo/pulls/3445#issuecomment-1789636'); const page = await login({browser}, workerInfo); await page.goto('/user2/repo1/pulls/5'); // toggle to WIP await toggle_wip_to({page}, true); await check_wip({page}, true); // remove WIP await toggle_wip_to({page}, false); await check_wip({page}, false); }); test('manual edit', async ({browser}, workerInfo) => { test.skip(workerInfo.project.name === 'Mobile Safari', 'Unable to get tests working on Safari Mobile, see https://codeberg.org/forgejo/forgejo/pulls/3445#issuecomment-1789636'); const page = await login({browser}, workerInfo); await page.goto('/user2/repo1/pulls/5'); // manually edit title to another prefix await page.locator('#issue-title-edit-show').click(); await page.locator('#issue-title-editor input').fill(`[WIP] ${prTitle}`); await page.getByText('Save').click(); await check_wip({page}, true); // remove again await toggle_wip_to({page}, false); await check_wip({page}, false); }); test('maximum title length', async ({browser}, workerInfo) => { test.skip(workerInfo.project.name === 'Mobile Safari', 'Unable to get tests working on Safari Mobile, see https://codeberg.org/forgejo/forgejo/pulls/3445#issuecomment-1789636'); const page = await login({browser}, workerInfo); await page.goto('/user2/repo1/pulls/5'); // check maximum title length is handled gracefully const maxLenStr = prTitle + 'a'.repeat(240); await page.locator('#issue-title-edit-show').click(); await page.locator('#issue-title-editor input').fill(maxLenStr); await page.getByText('Save').click(); await expect(page.locator('h1')).toContainText(maxLenStr); await check_wip({page}, false); await toggle_wip_to({page}, true); await check_wip({page}, true); await expect(page.locator('h1')).toContainText(maxLenStr); await toggle_wip_to({page}, false); await check_wip({page}, false); await expect(page.locator('h1')).toContainText(maxLenStr); }); }); test('Issue: Labels', async ({browser}, workerInfo) => { test.skip(workerInfo.project.name === 'Mobile Safari', 'Unable to get tests working on Safari Mobile, see https://codeberg.org/forgejo/forgejo/pulls/3445#issuecomment-1789636'); async function submitLabels({page}: {page: Page}) { const submitted = page.waitForResponse('/user2/repo1/issues/labels'); await page.locator('textarea').first().click(); // close via unrelated element await submitted; await page.waitForLoadState(); } const page = await login({browser}, workerInfo); // select label list in sidebar only const labelList = page.locator('.issue-content-right .labels-list a'); const response = await page.goto('/user2/repo1/issues/1'); expect(response?.status()).toBe(200); // restore initial state await page.locator('.select-label').click(); const responsePromise = page.waitForResponse('/user2/repo1/issues/labels'); await page.getByText('Clear labels').click(); await responsePromise; await expect(labelList.filter({hasText: 'label1'})).toBeHidden(); await expect(labelList.filter({hasText: 'label2'})).toBeHidden(); // add both labels await page.locator('.select-label').click(); // label search could be tested this way: // await page.locator('.select-label input').fill('label2'); await page.locator('.select-label .item').filter({hasText: 'label2'}).click(); await page.locator('.select-label .item').filter({hasText: 'label1'}).click(); await submitLabels({page}); await expect(labelList.filter({hasText: 'label2'})).toBeVisible(); await expect(labelList.filter({hasText: 'label1'})).toBeVisible(); // test removing label2 again // due to a race condition, the page could still be "reloading", // closing the dropdown after it was clicked. // Retry the interaction as a group // also see https://playwright.dev/docs/test-assertions#expecttopass await expect(async () => { await page.locator('.select-label').click(); await page.locator('.select-label .item').filter({hasText: 'label2'}).click(); }).toPass(); await submitLabels({page}); await expect(labelList.filter({hasText: 'label2'})).toBeHidden(); await expect(labelList.filter({hasText: 'label1'})).toBeVisible(); }); test('Issue: Assignees', async ({browser}, workerInfo) => { test.skip(workerInfo.project.name === 'Mobile Safari', 'Unable to get tests working on Safari Mobile, see https://codeberg.org/forgejo/forgejo/pulls/3445#issuecomment-1789636'); const page = await login({browser}, workerInfo); // select label list in sidebar only const assigneesList = page.locator('.issue-content-right .assignees.list .selected .item a'); const response = await page.goto('/org3/repo3/issues/1'); expect(response?.status()).toBe(200); // Clear all assignees await page.locator('.select-assignees-modify.dropdown').click(); await page.locator('.select-assignees-modify.dropdown .no-select.item').click(); await expect(assigneesList.filter({hasText: 'user2'})).toBeHidden(); await expect(assigneesList.filter({hasText: 'user4'})).toBeHidden(); await expect(page.locator('.ui.assignees.list .item.no-select')).toBeVisible(); await expect(page.locator('.select-assign-me')).toBeVisible(); // Assign other user (with searchbox) await page.locator('.select-assignees-modify.dropdown').click(); await page.type('.select-assignees-modify .menu .search input', 'user4'); await expect(page.locator('.select-assignees-modify .menu .item').filter({hasText: 'user2'})).toBeHidden(); await expect(page.locator('.select-assignees-modify .menu .item').filter({hasText: 'user4'})).toBeVisible(); await page.locator('.select-assignees-modify .menu .item').filter({hasText: 'user4'}).click(); await page.locator('.select-assignees-modify.dropdown').click(); await expect(assigneesList.filter({hasText: 'user4'})).toBeVisible(); // remove user4 await page.locator('.select-assignees-modify.dropdown').click(); await page.locator('.select-assignees-modify .menu .item').filter({hasText: 'user4'}).click(); await page.locator('.select-assignees-modify.dropdown').click(); await expect(page.locator('.ui.assignees.list .item.no-select')).toBeVisible(); await expect(assigneesList.filter({hasText: 'user4'})).toBeHidden(); // Test assign me await page.locator('.ui.assignees .select-assign-me').click(); await expect(assigneesList.filter({hasText: 'user2'})).toBeVisible(); await expect(page.locator('.ui.assignees.list .item.no-select')).toBeHidden(); }); test('New Issue: Assignees', async ({browser}, workerInfo) => { test.skip(workerInfo.project.name === 'Mobile Safari', 'Unable to get tests working on Safari Mobile, see https://codeberg.org/forgejo/forgejo/pulls/3445#issuecomment-1789636'); const page = await login({browser}, workerInfo); // select label list in sidebar only const assigneesList = page.locator('.issue-content-right .assignees.list .selected .item'); const response = await page.goto('/org3/repo3/issues/new'); expect(response?.status()).toBe(200); // preconditions await expect(page.locator('.ui.assignees.list .item.no-select')).toBeVisible(); await expect(assigneesList.filter({hasText: 'user2'})).toBeHidden(); await expect(assigneesList.filter({hasText: 'user4'})).toBeHidden(); // Assign other user (with searchbox) await page.locator('.select-assignees.dropdown').click(); await page.fill('.select-assignees .menu .search input', 'user4'); await expect(page.locator('.select-assignees .menu .item').filter({hasText: 'user2'})).toBeHidden(); await expect(page.locator('.select-assignees .menu .item').filter({hasText: 'user4'})).toBeVisible(); await page.locator('.select-assignees .menu .item').filter({hasText: 'user4'}).click(); await page.locator('.select-assignees.dropdown').click(); await expect(assigneesList.filter({hasText: 'user4'})).toBeVisible(); // remove user4 await page.locator('.select-assignees.dropdown').click(); await page.locator('.select-assignees .menu .item').filter({hasText: 'user4'}).click(); await page.locator('.select-assignees.dropdown').click(); await expect(page.locator('.ui.assignees.list .item.no-select')).toBeVisible(); await expect(assigneesList.filter({hasText: 'user4'})).toBeHidden(); // Test assign me await page.locator('.ui.assignees .select-assign-me').click(); await expect(assigneesList.filter({hasText: 'user2'})).toBeVisible(); await expect(page.locator('.ui.assignees.list .item.no-select')).toBeHidden(); await page.locator('.select-assignees.dropdown').click(); await page.fill('.select-assignees .menu .search input', ''); await page.locator('.select-assignees.dropdown .no-select.item').click(); await expect(page.locator('.select-assign-me')).toBeVisible(); }); test('Issue: Milestone', async ({browser}, workerInfo) => { test.skip(workerInfo.project.name === 'Mobile Safari', 'Unable to get tests working on Safari Mobile, see https://codeberg.org/forgejo/forgejo/pulls/3445#issuecomment-1789636'); const page = await login({browser}, workerInfo); const response = await page.goto('/user2/repo1/issues/1'); expect(response?.status()).toBe(200); const selectedMilestone = page.locator('.issue-content-right .select-milestone.list'); const milestoneDropdown = page.locator('.issue-content-right .select-milestone.dropdown'); await expect(selectedMilestone).toContainText('No milestone'); // Add milestone. await milestoneDropdown.click(); await page.getByRole('option', {name: 'milestone1'}).click(); await expect(selectedMilestone).toContainText('milestone1'); await expect(page.locator('.timeline-item.event').last()).toContainText('user2 added this to the milestone1 milestone'); // Clear milestone. await milestoneDropdown.click(); await page.getByText('Clear milestone', {exact: true}).click(); await expect(selectedMilestone).toContainText('No milestone'); await expect(page.locator('.timeline-item.event').last()).toContainText('user2 removed this from the milestone1 milestone'); }); test('New Issue: Milestone', async ({browser}, workerInfo) => { test.skip(workerInfo.project.name === 'Mobile Safari', 'Unable to get tests working on Safari Mobile, see https://codeberg.org/forgejo/forgejo/pulls/3445#issuecomment-1789636'); const page = await login({browser}, workerInfo); const response = await page.goto('/user2/repo1/issues/new'); expect(response?.status()).toBe(200); const selectedMilestone = page.locator('.issue-content-right .select-milestone.list'); const milestoneDropdown = page.locator('.issue-content-right .select-milestone.dropdown'); await expect(selectedMilestone).toContainText('No milestone'); // Add milestone. await milestoneDropdown.click(); await page.getByRole('option', {name: 'milestone1'}).click(); await expect(selectedMilestone).toContainText('milestone1'); // Clear milestone. await milestoneDropdown.click(); await page.getByText('Clear milestone', {exact: true}).click(); await expect(selectedMilestone).toContainText('No milestone'); });