diff --git a/package-lock.json b/package-lock.json
index 70ba86f2b46787a6c30dc7bf49fc944c1facdad7..ce158c1d6b8d81fff31166cc3dbb8756cb359481 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -43,6 +43,7 @@
         "eslint-config-standard": "^17.0.0",
         "eslint-plugin-chai-expect": "^3.0.0",
         "eslint-plugin-chai-friendly": "^0.7.2",
+        "eslint-plugin-cypress": "^2.15.1",
         "eslint-plugin-import": "^2.26.0",
         "eslint-plugin-mocha": "^10.1.0",
         "eslint-plugin-node": "^11.1.0",
@@ -46237,7 +46238,6 @@
         "es6-promise": "^4.2.8",
         "escodegen": "^2.0.0",
         "eslint-config-standard-jsx": "^11.0.0",
-        "eslint-plugin-cypress": "^2.15.1",
         "eslint-plugin-jsx-a11y": "^6.7.1",
         "eslint-plugin-react": "^7.32.2",
         "eslint-plugin-react-hooks": "^4.6.0",
@@ -55100,7 +55100,6 @@
         "es6-promise": "^4.2.8",
         "escodegen": "^2.0.0",
         "eslint-config-standard-jsx": "^11.0.0",
-        "eslint-plugin-cypress": "^2.15.1",
         "eslint-plugin-jsx-a11y": "^6.7.1",
         "eslint-plugin-react": "^7.32.2",
         "eslint-plugin-react-hooks": "^4.6.0",
diff --git a/package.json b/package.json
index 639c5107eaeb656649540243e4757a44d677d72c..ee8cb227b7b0ea68332df8969b76ef0d0dbc6c61 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
     "eslint-config-standard": "^17.0.0",
     "eslint-plugin-chai-expect": "^3.0.0",
     "eslint-plugin-chai-friendly": "^0.7.2",
+    "eslint-plugin-cypress": "^2.15.1",
     "eslint-plugin-import": "^2.26.0",
     "eslint-plugin-mocha": "^10.1.0",
     "eslint-plugin-node": "^11.1.0",
diff --git a/server-ce/.eslintrc b/server-ce/.eslintrc
index 492adda1543eca5e5815f2e415a9c561bb6db12f..3a2bb3247c5450312a4e4b3bceea73cb3340c4c0 100644
--- a/server-ce/.eslintrc
+++ b/server-ce/.eslintrc
@@ -13,5 +13,9 @@
   "rules": {
     // Do not allow importing of implicit dependencies.
     "import/no-extraneous-dependencies": "error"
-  }
+  },
+  "overrides": [
+    // Extra rules for Cypress tests
+    { "files": ["**/*.spec.ts"], "extends": ["plugin:cypress/recommended"] }
+  ]
 }
diff --git a/server-ce/test/create-and-compile-project.spec.ts b/server-ce/test/create-and-compile-project.spec.ts
index c3eea10c600725152f189981c9bb82763062830d..a875fb1d5503fe0bcd18f227417d981a08fce9bd 100644
--- a/server-ce/test/create-and-compile-project.spec.ts
+++ b/server-ce/test/create-and-compile-project.spec.ts
@@ -8,11 +8,10 @@ describe('Project creation and compilation', function () {
     // this is the first project created, the welcome screen is displayed instead of the project list
     createProject('test-project', { isFirstProject: true })
     cy.url().should('match', /\/project\/[a-fA-F0-9]{24}/)
-    cy.findByText('\\maketitle')
-      .parent()
-      .click()
-      .type('\n\\section{{}Test Section}')
+    cy.findByText('\\maketitle').parent().click()
+    cy.findByText('\\maketitle').parent().type('\n\\section{{}Test Section}')
     // Wait for the PDF compilation throttling
+    // eslint-disable-next-line cypress/no-unnecessary-waiting
     cy.wait(3000)
     cy.findByText('Recompile').click()
     cy.get('.pdf-viewer').should('contain.text', 'Test Section')
@@ -62,10 +61,7 @@ describe('Project creation and compilation', function () {
       cy.findByLabelText('Select a File').select('frog.jpg')
       cy.findByText('Create').click()
     })
-    // FIXME: should be aria-labeled or data-test-id
-    cy.get('.file-tree').first().within(() => {
-      cy.findByText('frog.jpg').click()
-    })
+    cy.findByTestId('file-tree').findByText('frog.jpg').click()
     cy.findByText('Another project')
       .should('have.attr', 'href')
       .then(href => {
@@ -121,9 +117,7 @@ describe('Project creation and compilation', function () {
       cy.url().should('include', targetProjectId)
     })
 
-    cy.get('.file-tree').first().within(() => {
-      cy.findByText('frog.jpg').click()
-    })
+    cy.findByTestId('file-tree').findByText('frog.jpg').click()
     cy.findByText('Another project')
       .should('have.attr', 'href')
       .then(href => {
diff --git a/services/web/app/views/project/editor/file-tree-react.pug b/services/web/app/views/project/editor/file-tree-react.pug
index 9db18c51300fe661453eeb0ab10343b5d6ec046e..8895a86161e34572aaab206c909e6e16608fc3ac 100644
--- a/services/web/app/views/project/editor/file-tree-react.pug
+++ b/services/web/app/views/project/editor/file-tree-react.pug
@@ -8,7 +8,7 @@ aside.editor-sidebar.full-size(
 	vertical-resizable-panes-resize-on="left-pane-resize-all"
 )
 
-	.file-tree(
+	div(
 		ng-controller="ReactFileTreeController"
 		vertical-resizable-top
 	)
diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-root.tsx b/services/web/frontend/js/features/file-tree/components/file-tree-root.tsx
index 93642db1cf7efbdf0adeff02201dff84ff6ee20d..75e5c2a3c73d3c567e292ee3d1592a0596290510 100644
--- a/services/web/frontend/js/features/file-tree/components/file-tree-root.tsx
+++ b/services/web/frontend/js/features/file-tree/components/file-tree-root.tsx
@@ -49,7 +49,11 @@ const FileTreeRoot = React.memo<{
   if (!isReady) return null
 
   return (
-    <div className="file-tree" ref={setFileTreeContainer}>
+    <div
+      className="file-tree"
+      data-testid="file-tree"
+      ref={setFileTreeContainer}
+    >
       {fileTreeContainer && (
         <FileTreeContext
           refProviders={refProviders}
diff --git a/services/web/package.json b/services/web/package.json
index 38dff5f95db925279ce46dd78a2285865959a1db..f19686265875ab66d29ef15cc01134dc0f1c2c5f 100644
--- a/services/web/package.json
+++ b/services/web/package.json
@@ -284,7 +284,6 @@
     "es6-promise": "^4.2.8",
     "escodegen": "^2.0.0",
     "eslint-config-standard-jsx": "^11.0.0",
-    "eslint-plugin-cypress": "^2.15.1",
     "eslint-plugin-jsx-a11y": "^6.7.1",
     "eslint-plugin-react": "^7.32.2",
     "eslint-plugin-react-hooks": "^4.6.0",