@@ -4,79 +4,140 @@ test('Create and delete a project', async ({ page }) => {
44 await page . goto ( '/projects' ) ;
55 await waitPageLoading ( page ) ;
66
7- // Create a new project with a random name
87 const randomProjectName = Math . random ( ) . toString ( 36 ) . substring ( 7 ) ;
9- const projectNameInput = page . locator ( '[name="projectName"]' ) ;
10- await projectNameInput . fill ( randomProjectName ) ;
11- await projectNameInput . blur ( ) ;
12- const createProjectBtn = page . getByRole ( 'button' , { name : 'Create new project' } ) ;
13- await createProjectBtn . waitFor ( ) ;
14- await createProjectBtn . click ( ) ;
15-
16- // Verify that the user is redirected to the project page
17- await page . waitForURL ( / \/ p r o j e c t s \/ \d + / ) ;
18- await expect ( page . locator ( 'h1:not(.modal-title)' ) ) . toHaveText (
19- new RegExp ( 'Project ' + randomProjectName + ' #\\d+' )
20- ) ;
21-
22- // Go back to projects list
23- await page . goto ( '/projects' ) ;
24- await waitPageLoading ( page ) ;
25- await expect ( page . getByRole ( 'cell' , { name : randomProjectName } ) ) . toHaveCount ( 1 ) ;
268
27- // Get project row
9+ await test . step ( 'Create a new project' , async ( ) => {
10+ await page . getByRole ( 'button' , { name : 'Create new project' } ) . click ( ) ;
11+
12+ // Wait modal opening
13+ let modalTitle = page . locator ( '.modal.show .modal-title' ) ;
14+ await modalTitle . waitFor ( ) ;
15+ await expect ( modalTitle ) . toHaveText ( 'Create new project' ) ;
16+
17+ // Fill form and submit
18+ const projectNameInput = page . getByLabel ( 'Project name' ) ;
19+ await projectNameInput . fill ( randomProjectName ) ;
20+ const createProjectBtn = page . locator ( '.modal.show' ) . getByRole ( 'button' , { name : 'Confirm' } ) ;
21+ await createProjectBtn . click ( ) ;
22+
23+ // Verify that the user is redirected to the project page
24+ await page . waitForURL ( / \/ p r o j e c t s \/ \d + / ) ;
25+ await expect ( page . locator ( 'h1:not(.modal-title)' ) ) . toHaveText (
26+ new RegExp ( 'Project ' + randomProjectName + ' #\\d+' )
27+ ) ;
28+ } ) ;
29+
30+ await test . step ( 'Verify that new project is visible in projects page' , async ( ) => {
31+ // Go back to projects list
32+ await page . goto ( '/projects' ) ;
33+ await waitPageLoading ( page ) ;
34+ await expect ( page . getByRole ( 'cell' , { name : randomProjectName } ) ) . toHaveCount ( 1 ) ;
35+
36+ const projectRow = await getProjectRow ( page , randomProjectName ) ;
37+
38+ // Open project info modal
39+ const infoBtn = /** @type {import('@playwright/test').Locator } */ ( projectRow ) . getByRole (
40+ 'button' ,
41+ { name : 'Info' }
42+ ) ;
43+ await infoBtn . click ( ) ;
44+
45+ // Wait info modal
46+ let modalTitle = page . locator ( '.modal.show .modal-title' ) ;
47+ await modalTitle . waitFor ( ) ;
48+ await expect ( modalTitle ) . toHaveText ( 'Project ' + randomProjectName ) ;
49+ const items = await page . locator ( '.modal.show .modal-body' ) . getByRole ( 'listitem' ) . all ( ) ;
50+ expect ( items . length ) . toEqual ( 4 ) ;
51+ expect ( await items [ 1 ] . innerText ( ) ) . toEqual ( randomProjectName ) ;
52+ expect ( await items [ 3 ] . innerText ( ) ) . toEqual ( 'No' ) ;
53+
54+ let closeModalBtn = page . locator ( '.modal.show' ) . getByRole ( 'button' , { name : 'Close' } ) ;
55+ await closeModalBtn . click ( ) ;
56+ } ) ;
57+
58+ await test . step ( 'Search the project' , async ( ) => {
59+ await page . getByPlaceholder ( 'Search' ) . fill ( randomProjectName ) ;
60+ expect ( await page . getByRole ( 'row' ) . count ( ) ) . toEqual ( 2 ) ;
61+
62+ await page . getByPlaceholder ( 'Search' ) . fill ( `${ randomProjectName } -foo` ) ;
63+ expect ( await page . getByRole ( 'row' ) . count ( ) ) . toEqual ( 1 ) ;
64+
65+ await page . getByPlaceholder ( 'Search' ) . fill ( '' ) ;
66+ } ) ;
67+
68+ await test . step ( 'Attempt to create a project with the same name' , async ( ) => {
69+ await page . getByRole ( 'button' , { name : 'Create new project' } ) . click ( ) ;
70+
71+ // Wait modal opening
72+ let modalTitle = page . locator ( '.modal.show .modal-title' ) ;
73+ await modalTitle . waitFor ( ) ;
74+ await expect ( modalTitle ) . toHaveText ( 'Create new project' ) ;
75+
76+ // Fill form and submit
77+ const projectNameInput = page . getByLabel ( 'Project name' ) ;
78+ await projectNameInput . fill ( randomProjectName ) ;
79+ const createProjectBtn = page . locator ( '.modal.show' ) . getByRole ( 'button' , { name : 'Confirm' } ) ;
80+ await createProjectBtn . click ( ) ;
81+
82+ // Check validation error
83+ await page . waitForFunction ( ( projectName ) => {
84+ const invalidFeeback = document . querySelector ( '.modal.show .invalid-feedback' ) ;
85+ if ( invalidFeeback instanceof HTMLElement ) {
86+ return invalidFeeback . innerText . includes ( `Project name (${ projectName } ) already in use` ) ;
87+ }
88+ return false ;
89+ } , randomProjectName ) ;
90+
91+ // Close modal
92+ const closeModalBtn = page . locator ( '.modal.show' ) . getByRole ( 'button' , { name : 'Cancel' } ) ;
93+ await closeModalBtn . click ( ) ;
94+ } ) ;
95+
96+ await test . step ( 'Delete project' , async ( ) => {
97+ const projectRow = await getProjectRow ( page , randomProjectName ) ;
98+
99+ // Click on the delete project button related to the current project
100+ const deleteBtn = /** @type {import('@playwright/test').Locator } */ ( projectRow ) . getByRole (
101+ 'button' ,
102+ { name : 'Delete' }
103+ ) ;
104+ await deleteBtn . click ( ) ;
105+
106+ // Wait confirm action modal
107+ let modalTitle = page . locator ( '.modal.show .modal-title' ) ;
108+ await modalTitle . waitFor ( ) ;
109+ await expect ( modalTitle ) . toHaveText ( 'Confirm action' ) ;
110+ await expect ( page . locator ( '.modal.show .modal-body' ) ) . toContainText (
111+ 'Delete project ' + randomProjectName
112+ ) ;
113+
114+ // Confirm the deletion of the project
115+ await page . getByRole ( 'button' , { name : 'Confirm' } ) . click ( ) ;
116+
117+ await page . waitForFunction ( ( projectName ) => {
118+ const projectNames = [ ...document . querySelectorAll ( 'table td:nth-child(2)' ) ] . map (
119+ ( c ) => /** @type {HTMLElement } */ ( c ) . innerText
120+ ) ;
121+ return ! projectNames . includes ( projectName ) ;
122+ } , randomProjectName ) ;
123+ await expect ( page . getByRole ( 'cell' , { name : randomProjectName } ) ) . toHaveCount ( 0 ) ;
124+ } ) ;
125+ } ) ;
126+
127+ /**
128+ * @param {import('@playwright/test').Page } page
129+ * @param {string } projectName
130+ * @returns {Promise<import('@playwright/test').Locator> }
131+ */
132+ async function getProjectRow ( page , projectName ) {
28133 const rows = await page . getByRole ( 'row' ) . all ( ) ;
29134 let projectRow ;
30135 for ( const row of rows ) {
31- if ( ( await row . getByRole ( 'cell' , { name : randomProjectName } ) . count ( ) ) === 1 ) {
136+ if ( ( await row . getByRole ( 'cell' , { name : projectName } ) . count ( ) ) === 1 ) {
32137 projectRow = row ;
33138 break ;
34139 }
35140 }
36141 expect ( projectRow ) . toBeDefined ( ) ;
37-
38- // Open project info modal
39- const infoBtn = /** @type {import('@playwright/test').Locator } */ ( projectRow ) . getByRole (
40- 'button' ,
41- { name : 'Info' }
42- ) ;
43- await infoBtn . click ( ) ;
44-
45- // Wait info modal
46- let modalTitle = page . locator ( '.modal.show .modal-title' ) ;
47- await modalTitle . waitFor ( ) ;
48- await expect ( modalTitle ) . toHaveText ( 'Project ' + randomProjectName ) ;
49- const items = await page . locator ( '.modal.show .modal-body' ) . getByRole ( 'listitem' ) . all ( ) ;
50- expect ( items . length ) . toEqual ( 4 ) ;
51- expect ( await items [ 1 ] . innerText ( ) ) . toEqual ( randomProjectName ) ;
52- expect ( await items [ 3 ] . innerText ( ) ) . toEqual ( 'No' ) ;
53-
54- let closeModalBtn = page . locator ( '.modal.show' ) . getByRole ( 'button' , { name : 'Close' } ) ;
55- await closeModalBtn . click ( ) ;
56-
57- // Click on the delete project button related to the current project
58- const deleteBtn = /** @type {import('@playwright/test').Locator } */ ( projectRow ) . getByRole (
59- 'button' ,
60- { name : 'Delete' }
61- ) ;
62- await deleteBtn . click ( ) ;
63-
64- // Wait confirm action modal
65- modalTitle = page . locator ( '.modal.show .modal-title' ) ;
66- await modalTitle . waitFor ( ) ;
67- await expect ( modalTitle ) . toHaveText ( 'Confirm action' ) ;
68- await expect ( page . locator ( '.modal.show .modal-body' ) ) . toContainText (
69- 'Delete project ' + randomProjectName
70- ) ;
71-
72- // Confirm the deletion of the project
73- await page . getByRole ( 'button' , { name : 'Confirm' } ) . click ( ) ;
74-
75- await page . waitForFunction ( ( projectName ) => {
76- const projectNames = [ ...document . querySelectorAll ( 'table td:nth-child(2)' ) ] . map (
77- ( c ) => /** @type {HTMLElement } */ ( c ) . innerText
78- ) ;
79- return ! projectNames . includes ( projectName ) ;
80- } , randomProjectName ) ;
81- await expect ( page . getByRole ( 'cell' , { name : randomProjectName } ) ) . toHaveCount ( 0 ) ;
82- } ) ;
142+ return /** @type {import('@playwright/test').Locator } */ ( projectRow ) ;
143+ }
0 commit comments