Skip to content

Commit f1b98d1

Browse files
fnetXforgejo-backport-action
authored andcommitted
tests(e2e): Test new repo dialog and behaviour
- screenshots and basic accessibility scan of collapsed and expanded sections - the dropdowns do not pass the accessibility checks, but I haven't found an easy fix - I manually confirmed the dropdown behaviour via orca and firefox, though (cherry picked from commit 8d829a9)
1 parent 662b385 commit f1b98d1

File tree

3 files changed

+152
-0
lines changed

3 files changed

+152
-0
lines changed

tests/e2e/repo-new.test.e2e.ts

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// @watch start
2+
// templates/repo/create**.tmpl
3+
// web_src/css/{form,repo}.css
4+
// @watch end
5+
6+
import {expect} from '@playwright/test';
7+
import {test, dynamic_id, save_visual, login_user, login} from './utils_e2e.ts';
8+
import {validate_form} from './shared/forms.ts';
9+
10+
test.beforeAll(async ({browser}, workerInfo) => {
11+
await login_user(browser, workerInfo, 'user2');
12+
});
13+
14+
test('New repo: invalid', async ({browser}, workerInfo) => {
15+
const page = await login({browser}, workerInfo);
16+
const response = await page.goto('/repo/create');
17+
expect(response?.status()).toBe(200);
18+
// check that relevant form content is hidden or available
19+
await expect(page.getByRole('group', {name: 'Use a template You can select'}).getByRole('combobox')).toBeVisible();
20+
await expect(page.getByText('.gitignore Select .gitignore')).toBeHidden();
21+
await expect(page.getByText('Labels Select a label set')).toBeHidden();
22+
await validate_form({page}, 'fieldset');
23+
await save_visual(page);
24+
25+
await page.getByLabel('Repository name').fill('*invalid');
26+
await page.getByRole('button', {name: 'Create repository'}).click();
27+
await expect(page.getByText('Repository name should contain only alphanumeric')).toBeVisible();
28+
await save_visual(page);
29+
});
30+
31+
test('New repo: initialize', async ({browser}, workerInfo) => {
32+
const page = await login({browser}, workerInfo);
33+
const response = await page.goto('/repo/create');
34+
expect(response?.status()).toBe(200);
35+
// check that relevant form content is hidden or available
36+
await expect(page.getByRole('group', {name: 'Use a template You can select'}).getByRole('combobox')).toBeVisible();
37+
await expect(page.getByText('.gitignore Select .gitignore')).toBeHidden();
38+
// fill initialization section
39+
await page.getByText('Start the Git history with').click();
40+
await page.getByText('Select .gitignore templates').click();
41+
await page.getByLabel('.gitignore Select .gitignore').fill('Go');
42+
await page.getByRole('option', {name: 'Go', exact: true}).click();
43+
await page.keyboard.press('Escape');
44+
await page.getByLabel('License Select a license file').click();
45+
await page.getByRole('option', {name: 'MIT', exact: true}).click();
46+
await page.keyboard.press('Escape');
47+
// add advanced settings
48+
await page.getByText('Click to expand').click();
49+
await page.getByPlaceholder('master').fill('main');
50+
await page.getByLabel('Make repository a template').check();
51+
52+
await validate_form({page}, 'fieldset');
53+
await save_visual(page);
54+
const reponame = dynamic_id();
55+
await page.getByLabel('Repository name').fill(reponame);
56+
await page.getByRole('button', {name: 'Create repository'}).click();
57+
await expect(page.getByRole('link', {name: '.gitignore'})).toBeVisible();
58+
await expect(page.getByRole('link', {name: 'LICENSE', exact: true})).toBeVisible();
59+
if (!workerInfo.project.name.includes('Mobile')) {
60+
await expect(page.getByText('Template', {exact: true})).toBeVisible();
61+
}
62+
await save_visual(page);
63+
});
64+
65+
test('New repo: initialize later', async ({browser}, workerInfo) => {
66+
const page = await login({browser}, workerInfo);
67+
const response = await page.goto('/repo/create');
68+
expect(response?.status()).toBe(200);
69+
70+
const reponame = dynamic_id();
71+
await page.getByLabel('Repository name').fill(reponame);
72+
await page.getByPlaceholder('Enter short description').fill(`Description for repo ${reponame}`);
73+
await page.getByText('Click to expand').click();
74+
await page.getByPlaceholder('master').fill('devbranch');
75+
await validate_form({page}, 'fieldset');
76+
await page.getByRole('button', {name: 'Create repository'}).click();
77+
expect(page.url()).toBe(`http://localhost:3003/user2/${reponame}`);
78+
await expect(page.getByRole('link', {name: 'New file'})).toBeVisible();
79+
await expect(page.getByRole('heading', {name: 'Creating a new repository on'})).toBeVisible();
80+
await save_visual(page);
81+
82+
// add a README
83+
await page.getByRole('link', {name: 'New file'}).click();
84+
// wait for loading spinner to disappear
85+
// Otherwise, filling the filename might not populate the tree_path form field or preview tab
86+
// The editor has race conditions, likely related to https://codeberg.org/forgejo/forgejo/issues/3371
87+
await expect(page.locator('.is-loading')).toBeHidden();
88+
await page.locator('.view-lines').click();
89+
await page.keyboard.type('# Heading\n\nHello Forgejo!');
90+
await page.getByPlaceholder('Name your file…').fill('README.md');
91+
await expect(page.getByText('Preview')).toBeVisible();
92+
await page.getByPlaceholder('Add "<filename>"').fill('My first commit message');
93+
await page.getByRole('button', {name: 'Commit changes'}).click();
94+
expect(page.url()).toBe(`http://localhost:3003/user2/${reponame}/src/branch/devbranch/README.md`);
95+
await expect(page.getByRole('link', {name: 'My first commit message'})).toBeVisible();
96+
await expect(page.getByText('Hello Forgejo!')).toBeVisible();
97+
await save_visual(page);
98+
});
99+
100+
test('New repo: from template', async ({browser}, workerInfo) => {
101+
test.skip(['Mobile Safari', 'webkit'].includes(workerInfo.project.name), 'WebKit browsers seem to have CORS issues with localhost here.');
102+
const page = await login({browser}, workerInfo);
103+
const response = await page.goto('/repo/create');
104+
expect(response?.status()).toBe(200);
105+
106+
const reponame = dynamic_id();
107+
await page.getByRole('group', {name: 'Use a template You can select'}).getByRole('combobox').click();
108+
await page.getByRole('option', {name: 'user27/template1'}).click();
109+
await page.getByText('Git content (Default branch)').click();
110+
await save_visual(page);
111+
await page.getByLabel('Repository name').fill(reponame);
112+
await page.getByRole('button', {name: 'Create repository'}).click();
113+
await expect(page.getByRole('link', {name: `${reponame}.log`})).toBeVisible();
114+
await save_visual(page);
115+
});
116+
117+
test('New repo: label set', async ({browser}, workerInfo) => {
118+
const page = await login({browser}, workerInfo);
119+
await page.goto('/repo/create');
120+
121+
const reponame = dynamic_id();
122+
await page.getByText('Click to expand').click();
123+
await page.getByLabel('Labels Select a label set').click();
124+
await page.getByRole('option', {name: 'Advanced (Kind/Bug, Kind/'}).click();
125+
// close dropdown via unrelated click
126+
await page.getByText('You can select an existing').click();
127+
await save_visual(page);
128+
await page.getByLabel('Repository name').fill(reponame);
129+
await page.getByRole('button', {name: 'Create repository'}).click();
130+
await page.goto(`/user2/${reponame}/issues`);
131+
await page.getByRole('link', {name: 'Labels'}).click();
132+
await expect(page.getByText('Kind/Bug Something is not')).toBeVisible();
133+
await save_visual(page);
134+
});

tests/e2e/shared/forms.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ export async function validate_form({page}: {page: Page}, scope: 'form' | 'field
77
'span[data-tooltip-content',
88
// exclude weird non-semantic HTML disabled content
99
'.disabled',
10+
// legacy dropdowns don't use semantic HTML yet,
11+
// avoid using these where possible
12+
'.ui.dropdown',
1013
];
1114
await accessibilityCheck({page}, [scope], excludedElements, []);
1215

tests/e2e/utils_e2e.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ export async function save_visual(page: Page) {
8181
await page.locator('.flex-item-body > relative-time').filter({hasText: /now|minute/}).evaluateAll((nodes) => {
8282
for (const node of nodes) node.outerHTML = 'relative time in repo';
8383
});
84+
// dynamically generated UUIDs
85+
await page.getByText('dyn-id-').evaluateAll((nodes) => {
86+
for (const node of nodes) node.innerHTML = node.innerHTML.replaceAll(/dyn-id-[a-f0-9-]+/g, 'dynamic-id');
87+
});
88+
// repeat above, work around https://github.com/microsoft/playwright/issues/34152
89+
await page.getByText('dyn-id-').evaluateAll((nodes) => {
90+
for (const node of nodes) node.innerHTML = node.innerHTML.replaceAll(/dyn-id-[a-f0-9-]+/g, 'dynamic-id');
91+
});
8492
await page.locator('relative-time').evaluateAll((nodes) => {
8593
for (const node of nodes) node.outerHTML = 'time element';
8694
});
@@ -97,6 +105,8 @@ export async function save_visual(page: Page) {
97105
page.locator('#repo_migrating'),
98106
// update order of recently created repos is not fully deterministic
99107
page.locator('.flex-item-main').filter({hasText: 'relative time in repo'}),
108+
// dynamic IDs in fixed-size inputs
109+
page.locator('input[value*="dyn-id-"]'),
100110
],
101111
});
102112
}
@@ -122,3 +132,8 @@ export async function create_temp_user(browser: Browser, workerInfo: TestInfo, r
122132

123133
return {context: await login_user(browser, workerInfo, username), username};
124134
}
135+
136+
// returns a random string with a pattern that can be filtered for screenshots automatically
137+
export function dynamic_id() {
138+
return `dyn-id-${globalThis.crypto.randomUUID()}`;
139+
}

0 commit comments

Comments
 (0)