diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b997fc39d2e0c08585ea8abef7c1b23bfe0cad78..3a71fbf6504a3fa1be50999b85ae290c42b82d9c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -230,6 +230,39 @@ wp-tests:
     - ./nix/build-proxy.sh wp-tests
   <<: *coverage
 
+ivette-tests:
+  stage: tests
+  allow_failure: true
+  image: "ocaml/opam:ubuntu-lts-ocaml-$OCAML"
+  before_script:
+    - sudo apt update
+    - sudo apt install -y xvfb curl bubblewrap unzip libnss3 libasound2
+    - sudo curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
+    - export NVM_DIR="$HOME/.nvm"
+    - '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"'
+    - '[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"'
+    - nvm install 16
+    - nvm use node 16
+    - corepack enable
+  script:
+    - opam switch create 4.13.1
+    - eval $(opam env)
+    - opam pin . -n
+    - opam depext frama-c --with-test
+    - opam install --deps-only .
+    - make clean && make && make -C ivette dist
+    - cd ivette
+    - cp dist/renderer/* dist/main/
+    - xvfb-run --auto-servernum -e /dev/stdout -s "-screen 0 1920x1080x24 -ac -nolisten tcp -nolisten unix" dune exec -- yarn playwright test --headed
+  artifacts:
+    paths:
+      - ivette/tests/test-results
+      - ivette/screenshots
+    when: always
+    expire_in: 1 day
+  tags:
+    - docker
+
 external-plugins:
   stage: tests
   script:
diff --git a/ivette/.gitignore b/ivette/.gitignore
index 08b3cc95e60a655d4d140fb6f410ec9dbedb4ebc..17050941e3b59363c860c148a3e62e7584eef111 100644
--- a/ivette/.gitignore
+++ b/ivette/.gitignore
@@ -18,3 +18,7 @@ yarn-error.log
 /icon.icns
 
 # --------------------------------------------------------------------------
+/tests/test-results/
+/screenshots/*
+/playwright-report/
+/playwright/.cache/
diff --git a/ivette/Makefile b/ivette/Makefile
index 5408087aa66a5362d6617a08b0898cb49371f312..1e54ceb9c4073f026e396fad918cb513429fca48 100644
--- a/ivette/Makefile
+++ b/ivette/Makefile
@@ -276,3 +276,21 @@ uninstall:
 endif
 
 # --------------------------------------------------------------------------
+# --- Ivette Tests
+# --------------------------------------------------------------------------
+tests: dist
+	@cp dist/renderer/* dist/main/
+	@echo "[Ivette] running tests"
+	@dune exec -- yarn playwright test
+
+tests-e2e: dist
+	@cp dist/renderer/* dist/main/
+	@echo "[Ivette] running tests (e2e)"
+	@dune exec -- yarn playwright test tests/e2e
+
+tests-monkey: dist
+	@cp dist/renderer/* dist/main/
+	@echo "[Ivette] running tests (monkey)"
+	@dune exec -- yarn playwright test tests/monkey
+
+# --------------------------------------------------------------------------
diff --git a/ivette/package.json b/ivette/package.json
index 645a55b5fb89ba3008bfccb6cdce020c4c2e2d64..0e79773d104bc8a69d760e5f3fcaeb8c560e57d5 100644
--- a/ivette/package.json
+++ b/ivette/package.json
@@ -9,7 +9,7 @@
   "description": "Frama-C GUI",
   "homepage": "https://frama-c.com/html/ivette.html",
   "scripts": {
-    "lint": "eslint --ext .ts,.tsx --format=compact ./src",
+    "lint": "eslint --ext .ts,.tsx --format=compact ./src ./tests",
     "typecheck": "tsc --noEmit",
     "typecheck:watch": "yarn run typecheck -- --watch",
     "build": "tsc",
@@ -28,6 +28,7 @@
     "@babel/preset-react": "^7.16.7",
     "@babel/preset-typescript": "",
     "@hot-loader/react-dom": "^16",
+    "@playwright/test": "^1.36.0",
     "@types/codemirror": "",
     "@types/cytoscape": "",
     "@types/estree": "^0.0.50",
@@ -63,16 +64,16 @@
   },
   "dependencies": {
     "@babel/runtime": "",
+    "@codemirror/commands": "6.1.0",
+    "@codemirror/lang-cpp": "6.0.1",
+    "@codemirror/language": "6.2.1",
+    "@codemirror/search": "6.2.3",
+    "@codemirror/state": "6.1.1",
+    "@codemirror/view": "6.2.3",
     "@fortawesome/fontawesome-free": "",
     "@types/diff": "",
     "@types/react-window": "",
     "codemirror": "^5.65.2",
-    "@codemirror/view": "6.2.3",
-    "@codemirror/state": "6.1.1",
-    "@codemirror/search": "6.2.3",
-    "@codemirror/language": "6.2.1",
-    "@codemirror/commands": "6.1.0",
-    "@codemirror/lang-cpp": "6.0.1",
     "cytoscape": "",
     "cytoscape-cola": "",
     "cytoscape-cose-bilkent": "",
@@ -82,6 +83,7 @@
     "cytoscape-panzoom": "",
     "cytoscape-popper": "",
     "diff": "",
+    "gremlins.js": "^2.2.0",
     "immutable": "",
     "lodash": "^4.17.21",
     "react": "^16",
diff --git a/ivette/playwright.config.ts b/ivette/playwright.config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b7a7d30b501a478d25023dd13f1a76087bee16d5
--- /dev/null
+++ b/ivette/playwright.config.ts
@@ -0,0 +1,94 @@
+/* ************************************************************************ */
+/*                                                                          */
+/*   This file is part of Frama-C.                                          */
+/*                                                                          */
+/*   Copyright (C) 2007-2023                                                */
+/*     CEA (Commissariat à l'énergie atomique et aux énergies               */
+/*          alternatives)                                                   */
+/*                                                                          */
+/*   you can redistribute it and/or modify it under the terms of the GNU    */
+/*   Lesser General Public License as published by the Free Software        */
+/*   Foundation, version 2.1.                                               */
+/*                                                                          */
+/*   It is distributed in the hope that it will be useful,                  */
+/*   but WITHOUT ANY WARRANTY; without even the implied warranty of         */
+/*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
+/*   GNU Lesser General Public License for more details.                    */
+/*                                                                          */
+/*   See the GNU Lesser General Public License version 2.1                  */
+/*   for more details (enclosed in the file licenses/LGPLv2.1).             */
+/*                                                                          */
+/* ************************************************************************ */
+
+import { defineConfig, devices } from '@playwright/test';
+
+/**
+ * Read environment variables from file.
+ * https://github.com/motdotla/dotenv
+ */
+// require('dotenv').config();
+
+const testDir = './tests';
+
+/**
+ * See https://playwright.dev/docs/test-configuration.
+ */
+export default defineConfig({
+  /* Directory to look for tests when executing 'yarn playwright test'. */
+  testDir: testDir,
+  /* Directory for test artifacts. */
+  outputDir: testDir.concat('/test-results'),
+  /* Run tests in files in parallel (set to false to avoid concurrency issues with Electron). */
+  fullyParallel: false,
+  /* 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: 1,
+  /* Reporter to use. See https://playwright.dev/docs/test-reporters. */
+  reporter: [['list', { printSteps: true }], ['html', { open: 'never' }]],
+  /* 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://127.0.0.1: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'] },
+    },
+
+    /* 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://127.0.0.1:3000',
+  //   reuseExistingServer: !process.env.CI,
+  // },
+});
diff --git a/ivette/src/dome/main/dome.ts b/ivette/src/dome/main/dome.ts
index fde22418299c5565e527a09fd89da3ff7a1edec8..c68ef03f2674f815df9c9862332e6cd70e6a54cb 100644
--- a/ivette/src/dome/main/dome.ts
+++ b/ivette/src/dome/main/dome.ts
@@ -37,22 +37,22 @@
    @module dome(main)
 */
 
-import _ from 'lodash';
-import fs from 'fs';
-import path from 'path';
+import installExtension, { REACT_DEVELOPER_TOOLS } from 'dome/devtools';
+import SYS, * as System from 'dome/system';
 import {
-  app,
-  ipcMain,
   BrowserWindow,
   BrowserWindowConstructorOptions,
   IpcMainEvent,
-  shell,
+  Rectangle,
+  app,
   dialog,
+  ipcMain,
   nativeTheme,
-  Rectangle,
+  shell,
 } from 'electron';
-import installExtension, { REACT_DEVELOPER_TOOLS } from 'dome/devtools';
-import SYS, * as System from 'dome/system';
+import fs from 'fs';
+import _ from 'lodash';
+import path from 'path';
 
 // --------------------------------------------------------------------------
 // --- Main Window Web Navigation
@@ -155,6 +155,11 @@ const APP_DIR = app.getPath('userData');
 const PATH_WINDOW_SETTINGS = path.join(APP_DIR, 'WindowSettings.json');
 const PATH_GLOBAL_SETTINGS = path.join(APP_DIR, 'GlobalSettings.json');
 
+const CLI_OPTION_SETTINGS = {
+  name: "--settings",
+  defaultValue: "DEFAULT",
+} as const;
+
 function saveGlobalSettings(): void {
   try {
     if (!fstat(APP_DIR)) fs.mkdirSync(APP_DIR);
@@ -215,7 +220,10 @@ function saveWindowConfig(handle: Handle): void {
     storage: handle.storage,
     devtools: handle.devtools,
   };
-  saveSettings(handle.config, configData);
+
+  if (process.argv.indexOf(CLI_OPTION_SETTINGS.name) === -1) {
+    saveSettings(handle.config, configData);
+  }
 }
 
 function windowSyncSettings(event: IpcMainEvent): void {
@@ -402,7 +410,20 @@ function createBrowserWindow(
     ...config,
   };
 
-  const configFile = isAppWindow ? lookupConfig(wdir) : PATH_WINDOW_SETTINGS;
+  let configFile = PATH_WINDOW_SETTINGS;
+  if (argv && argv.indexOf(CLI_OPTION_SETTINGS.name) >= 0) {
+    const settingsIdx = argv.indexOf(CLI_OPTION_SETTINGS.name);
+    const settings = argv[settingsIdx + 1];
+    if (settings !== CLI_OPTION_SETTINGS.defaultValue) {
+      configFile = argv[settingsIdx + 1];
+    }
+    argv = argv.slice(0, settingsIdx).concat(argv.slice(settingsIdx + 2));
+  } else if (isAppWindow) {
+    configFile = lookupConfig(wdir);
+  }
+
+  console.log('[Dome] Loading config file', configFile);
+
   const configData = loadSettings(configFile);
 
   const frame = jFrame(configData.frame);
@@ -539,6 +560,15 @@ function createPrimaryWindow(): void {
   const wdir = cwd === '/' ? app.getPath('home') : cwd;
   const cmd = stripElectronArgv({ wdir, argv: process.argv });
 
+  // Reset Settings if the associated argument is provided
+  const settingsIdx = cmd.argv.indexOf(CLI_OPTION_SETTINGS.name);
+  if (settingsIdx >= 0) {
+    const settings = cmd.argv[settingsIdx + 1];
+    if (settings === CLI_OPTION_SETTINGS.defaultValue) {
+      restoreAllDefaultSettings();
+    }
+  }
+
   // Initialize Theme
   const globals = obtainGlobalSettings();
   applyThemeSettings(globals);
@@ -629,6 +659,23 @@ function restoreDefaultSettings(): void {
   broadcast('dome.ipc.settings.defaults');
 }
 
+/**
+ * Resets the Global setting file and delete the Window setting file
+ * (which will be recreated in a default state when needed)
+ */
+function restoreAllDefaultSettings(): void {
+  GlobalSettings = {};
+  nativeTheme.themeSource = 'system';
+  saveGlobalSettings();
+  try {
+    if (fs.existsSync(PATH_WINDOW_SETTINGS)) {
+      fs.rmSync(PATH_WINDOW_SETTINGS);
+    }
+  } catch (error) {
+    console.warn(error);
+  }
+}
+
 ipcMain.on('dome.menu.settings', showSettingsWindow);
 ipcMain.on('dome.menu.defaults', restoreDefaultSettings);
 ipcMain.on('dome.app.paths', (event) => {
diff --git a/ivette/tests/README.md b/ivette/tests/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6e827583c84d781131b4b4abdaaa4742fc22cc36
--- /dev/null
+++ b/ivette/tests/README.md
@@ -0,0 +1,153 @@
+This document presents the framework for testing Ivette by describing its
+overall architecture, and how to launch current tests and write new ones.
+
+## Overall Architecture
+
+The framework is based on two main testing libraries:
+
+- `Playwright`: <https://playwright.dev/>
+- `Gremlins.js`: <https://github.com/marmelab/gremlins.js>
+
+`Playwright` is meant for end-to-end (e2e) testing, i.e. for testing specific
+behaviors, while `Gremlins.js` provides monkey testing, i.e. robustness/stress
+testing of the entire application.
+
+Here is how the framework is organized:
+
+- `e2e/` contains the end-to-end tests,
+- `monkey/` cointains the monkey tests,
+- `lib/` contains utilities for writing tests using the `Playwright`
+  infrastructure. These utilities are used both for e2e and monkey testing.
+
+## Executing tests
+
+**Requirement:** In order to execute the tests, Frama-C has to be built
+beforehand.
+
+Testing Ivette, in terms of both the e2e and monkey tests, amounts to the
+execution of the following commands from the Frama-C root directory:
+
+```sh
+$ make                         // builds Frama-C, if not already
+$ cd ivette
+$ make tests                   // builds Ivette and execute all tests
+```
+
+To execute the e2e tests only, the last command to execute is the following:
+
+```sh
+$ make tests-e2e
+```
+
+To execute the monkey tests only, the last command to execute is the following:
+
+```sh
+$ make tests-monkey
+```
+
+## Executing tests (Advanced)
+
+Whenever the execution of the tests does not need (re-)building Ivette, one can
+directly do the following from the Ivette root directory:
+
+```sh
+$ dune exec -- yarn playwright test
+```
+
+This is also useful for executing just a (list of) test(s). In such a case, do
+the following from the Ivette root directory:
+
+```sh
+$ dune exec -- yarn playwright test /path/to/test1 /path/to/test2
+```
+
+For more information, refer to the `Playwright`
+[documentation](https://playwright.dev/docs/running-tests).
+
+## Accessing tests report
+
+Upon a test failure, `Playwright` informs about the failing step, or assertion,
+with a message on the console. This should be sufficient to debug the failure.
+However, `Playwright` also writes down a report of the failure that can be
+accessed as follows from the Ivette root directory:
+
+```sh
+$ yarn playwright show-report
+```
+
+The previous command should open a browser tab showing the last recorded report;
+if not, such a report should be available at `http://localhost:9323`.
+
+## Writing end-to-end tests
+
+End-to-end testing is meant for testing specific Ivette behaviors. This is done
+by using the `Playwright` library, which is based on [expect
+assertionts](https://playwright.dev/docs/test-assertions) on elements of a web
+page at a given moment, named
+[locators](https://playwright.dev/docs/api/class-locator).
+
+A test for Ivette looks like this:
+
+```ts
+import { test } from "@playwright/test";
+import * as e2eService from "../libs/e2eService";
+
+test("<test description>", async () => {
+  const launchAppResult = await e2eService.launchApp(
+    <arguments>,
+  );
+
+  const electronApp = launchAppResult.app;
+  const window = launchAppResult.page;
+
+  // find/select HTML element via Playwright's
+  // [locators](https://playwright.dev/docs/locators].
+  const locator = await window.<locator>;
+
+  // perform a Playwright's [action](https://playwright.dev/docs/input)
+  // on the locator.
+  await locator.<action>;
+
+  // [test assertion](https://playwright.dev/docs/test-assertions) on a
+  // Playwright's value (e.g. locator) with respect to a Playwright's matcher.
+  await expect(<value>).<matcher>;
+
+  // exit app.
+  await electronApp.close();
+});
+```
+
+The Ivette testing framework abstracts the `Playwright`'s API by providing
+common utilities in the sub-directory `/tests/libs`. In particular,
+`/tests/libs/e2eService.ts` provides, and should be enriched with, common
+testing services for Ivette, while `/tests/libs/locatorsUtil.ts` provides, and
+should be enriched with, common locators for Ivette.
+
+Note that `/tests/libs/e2eService.ts` also provides with some examples of
+`<arguments>` to fed `e2eService.launchApp()` function with. In particular, use
+the `Dome`'s `--settings CLEAN` option for launching Ivette with default
+settings, and the `--settings </path/to/json-file-with-settings>`
+option for launching Ivette with particular settings.
+
+`Playwright` also provides an interactive way for identifying new locators.
+Adding `await window.pause()` inside a test will open an additional `Playwright`
+window with a `Pick locator` button at the bottom, which provides the necessary
+locator any selected element (i.e., it works similarly to the inspect
+functionality of most browser developer tools).
+
+Complete test scenarios are provided in the sub-directory `/tests/e2e/`.
+
+## Monkey Testing
+
+Monkey testing is meant for testing the Ivette robustness by performing a stress
+testing of the UI. This is done by using the `gremlins.js` library.
+
+Please refer to the [library
+documentation](https://github.com/marmelab/gremlins.js) for more details, or
+look at the `/tests/monkey/monkey-testing.spec.ts` for an example.
+
+Note that, to obtain reproducible tests, one should seed a randomizer (see the
+`randomizer` value in `monkey-testing.spec.ts` for an example). For that, one
+should also launch Ivette with either default settings, by using the
+`-settings CLEAN` option, or fixed settings, by using the `--settings
+</path/to/json-file-with-settings>` option.
diff --git a/ivette/tests/e2e/launch-app.spec.ts b/ivette/tests/e2e/launch-app.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e9e2ce889fdec3443b3bdb9d82d2fe9f0757961d
--- /dev/null
+++ b/ivette/tests/e2e/launch-app.spec.ts
@@ -0,0 +1,37 @@
+/* ************************************************************************ */
+/*                                                                          */
+/*   This file is part of Frama-C.                                          */
+/*                                                                          */
+/*   Copyright (C) 2007-2023                                                */
+/*     CEA (Commissariat à l'énergie atomique et aux énergies               */
+/*          alternatives)                                                   */
+/*                                                                          */
+/*   you can redistribute it and/or modify it under the terms of the GNU    */
+/*   Lesser General Public License as published by the Free Software        */
+/*   Foundation, version 2.1.                                               */
+/*                                                                          */
+/*   It is distributed in the hope that it will be useful,                  */
+/*   but WITHOUT ANY WARRANTY; without even the implied warranty of         */
+/*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
+/*   GNU Lesser General Public License for more details.                    */
+/*                                                                          */
+/*   See the GNU Lesser General Public License version 2.1                  */
+/*   for more details (enclosed in the file licenses/LGPLv2.1).             */
+/*                                                                          */
+/* ************************************************************************ */
+
+import { test } from "@playwright/test";
+import * as e2eService from "../libs/e2eService";
+
+test("launch app", async () => {
+  const launchAppResult = await e2eService.launchApp(
+    e2eService.argsDefaultLaunch,
+  );
+  const electronApp = launchAppResult.app;
+  const window = launchAppResult.page;
+
+  await window.screenshot({ path: "screenshots/e2e-app-launch.png" });
+
+  // Exit app.
+  await electronApp.close();
+});
diff --git a/ivette/tests/e2e/server-connection-file.spec.ts b/ivette/tests/e2e/server-connection-file.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7a379f024a14cc732092aaa3e8f879659dcda42a
--- /dev/null
+++ b/ivette/tests/e2e/server-connection-file.spec.ts
@@ -0,0 +1,37 @@
+/* ************************************************************************ */
+/*                                                                          */
+/*   This file is part of Frama-C.                                          */
+/*                                                                          */
+/*   Copyright (C) 2007-2023                                                */
+/*     CEA (Commissariat à l'énergie atomique et aux énergies               */
+/*          alternatives)                                                   */
+/*                                                                          */
+/*   you can redistribute it and/or modify it under the terms of the GNU    */
+/*   Lesser General Public License as published by the Free Software        */
+/*   Foundation, version 2.1.                                               */
+/*                                                                          */
+/*   It is distributed in the hope that it will be useful,                  */
+/*   but WITHOUT ANY WARRANTY; without even the implied warranty of         */
+/*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
+/*   GNU Lesser General Public License for more details.                    */
+/*                                                                          */
+/*   See the GNU Lesser General Public License version 2.1                  */
+/*   for more details (enclosed in the file licenses/LGPLv2.1).             */
+/*                                                                          */
+/* ************************************************************************ */
+
+import { test } from "@playwright/test";
+import * as e2eService from "../libs/e2eService";
+
+test("server connection with a C file to analyze", async () => {
+  const launchAppResult = await e2eService.launchApp(
+    e2eService.argsLaunchWithTestFile,
+  );
+  const electronApp = launchAppResult.app;
+  const window = launchAppResult.page;
+
+  await e2eService.testFileIsLoaded(window);
+
+  // Exit app.
+  await electronApp.close();
+});
diff --git a/ivette/tests/e2e/server-connection.spec.ts b/ivette/tests/e2e/server-connection.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..263384fd1ce7aaf0b5eae20a878977a8633a55ef
--- /dev/null
+++ b/ivette/tests/e2e/server-connection.spec.ts
@@ -0,0 +1,37 @@
+/* ************************************************************************ */
+/*                                                                          */
+/*   This file is part of Frama-C.                                          */
+/*                                                                          */
+/*   Copyright (C) 2007-2023                                                */
+/*     CEA (Commissariat à l'énergie atomique et aux énergies               */
+/*          alternatives)                                                   */
+/*                                                                          */
+/*   you can redistribute it and/or modify it under the terms of the GNU    */
+/*   Lesser General Public License as published by the Free Software        */
+/*   Foundation, version 2.1.                                               */
+/*                                                                          */
+/*   It is distributed in the hope that it will be useful,                  */
+/*   but WITHOUT ANY WARRANTY; without even the implied warranty of         */
+/*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
+/*   GNU Lesser General Public License for more details.                    */
+/*                                                                          */
+/*   See the GNU Lesser General Public License version 2.1                  */
+/*   for more details (enclosed in the file licenses/LGPLv2.1).             */
+/*                                                                          */
+/* ************************************************************************ */
+
+import { test } from "@playwright/test";
+import * as e2eService from "../libs/e2eService";
+
+test("check server connection", async () => {
+  const launchAppResult = await e2eService.launchApp(
+    e2eService.argsLaunchWithDefaultSettings,
+  );
+  const electronApp = launchAppResult.app;
+  const window = launchAppResult.page;
+
+  await e2eService.testServerIsStarted(window);
+
+  // Exit app.
+  await electronApp.close();
+});
diff --git a/ivette/tests/libs/e2eService.ts b/ivette/tests/libs/e2eService.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1de42c07e52ebf15a202b03ec1c6b212a9447494
--- /dev/null
+++ b/ivette/tests/libs/e2eService.ts
@@ -0,0 +1,108 @@
+/* ************************************************************************ */
+/*                                                                          */
+/*   This file is part of Frama-C.                                          */
+/*                                                                          */
+/*   Copyright (C) 2007-2023                                                */
+/*     CEA (Commissariat à l'énergie atomique et aux énergies               */
+/*          alternatives)                                                   */
+/*                                                                          */
+/*   you can redistribute it and/or modify it under the terms of the GNU    */
+/*   Lesser General Public License as published by the Free Software        */
+/*   Foundation, version 2.1.                                               */
+/*                                                                          */
+/*   It is distributed in the hope that it will be useful,                  */
+/*   but WITHOUT ANY WARRANTY; without even the implied warranty of         */
+/*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
+/*   GNU Lesser General Public License for more details.                    */
+/*                                                                          */
+/*   See the GNU Lesser General Public License version 2.1                  */
+/*   for more details (enclosed in the file licenses/LGPLv2.1).             */
+/*                                                                          */
+/* ************************************************************************ */
+
+import { ElectronApplication, Page, expect } from "@playwright/test";
+import { _electron as electron } from "playwright-core";
+import * as locs from "./locatorsUtil";
+
+/**
+ * Basic Electron configuration for Playwright e2e tests of Ivette
+ */
+export const argsDefaultLaunch: string[] = [
+  "./dist/main/main.js",
+  "--no-sandbox",
+];
+
+/**
+ * Electron configuration for Playwright e2e tests of Ivette's default settings
+ */
+export const argsLaunchWithDefaultSettings: string[] = [
+  "./dist/main/main.js",
+  "--no-sandbox",
+  "--settings",
+  "DEFAULT"
+];
+
+/**
+ * Electron configuration for Playwright e2e tests of Ivette on a C file
+ */
+export const argsLaunchWithTestFile: string[] = [
+  "./dist/main/main.js",
+  "--no-sandbox",
+  "--settings",
+  "./tests/settings.json",
+  "../tests/test/adpcm.c",
+];
+
+/**
+ * Basic Electron launch of Ivette for Playwright e2e tests
+ */
+export async function launchApp(
+  params: string[]
+): Promise<{ app: ElectronApplication; page: Page }> {
+  const electronApp = await electron.launch({
+    env: {
+      ...process.env,
+      NODE_ENV: "development",
+    },
+    args: params,
+  });
+
+  // Get the first window that the app opens, wait if necessary
+  const window = await electronApp.firstWindow();
+
+  return {
+    app: electronApp,
+    page: window,
+  };
+}
+
+export async function testServerIsStarted(window: Page): Promise<void> {
+  // Click on the Console tab in the right menu
+  await locs.getConsoleMenuItem(window).click();
+
+  // Check the server status in the header's button bar
+  await expect(locs.getStartServerButton(window)).toBeDisabled();
+  await expect(locs.getShutDownServerButton(window)).toBeEnabled();
+
+  // Check the server status in the console view
+  await expect(
+    locs.getConsoleView(window).getByText("[server] Socket server running.")
+  ).toBeVisible();
+
+  // Check the server status in the footer
+  await expect(locs.getServerStatusLabel(window)).toHaveText("ON");
+}
+
+export async function testFileIsLoaded(window: Page): Promise<void> {
+  await locs.getConsoleMenuItem(window).click();
+  // Check if a message is present in the console view to confirm the file is
+  // loaded
+  await expect(
+    locs.getConsoleView(window).getByText("adpcm.c (with preprocessing)")
+  ).toBeVisible();
+
+  // Check if the main function is visible in the functions view
+  await expect(
+    locs.getFunctionsSideBar(window).getByText("main", { exact: true })
+  ).toBeVisible();
+}
diff --git a/ivette/tests/libs/locatorsUtil.ts b/ivette/tests/libs/locatorsUtil.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7d57f5843c6e331941e9620a06509ea7602dc3f1
--- /dev/null
+++ b/ivette/tests/libs/locatorsUtil.ts
@@ -0,0 +1,67 @@
+/* ************************************************************************ */
+/*                                                                          */
+/*   This file is part of Frama-C.                                          */
+/*                                                                          */
+/*   Copyright (C) 2007-2023                                                */
+/*     CEA (Commissariat à l'énergie atomique et aux énergies               */
+/*          alternatives)                                                   */
+/*                                                                          */
+/*   you can redistribute it and/or modify it under the terms of the GNU    */
+/*   Lesser General Public License as published by the Free Software        */
+/*   Foundation, version 2.1.                                               */
+/*                                                                          */
+/*   It is distributed in the hope that it will be useful,                  */
+/*   but WITHOUT ANY WARRANTY; without even the implied warranty of         */
+/*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
+/*   GNU Lesser General Public License for more details.                    */
+/*                                                                          */
+/*   See the GNU Lesser General Public License version 2.1                  */
+/*   for more details (enclosed in the file licenses/LGPLv2.1).             */
+/*                                                                          */
+/* ************************************************************************ */
+
+import { Locator, Page } from "@playwright/test";
+
+/**
+ * Locator to select "Console" in the right menu
+ */
+export function getConsoleMenuItem(window: Page): Locator {
+  return window
+    .getByText("ViewsConsoleSource Code")
+    .getByText("Console")
+    .first();
+}
+
+/**
+ * Locator to select the Start button in the top button bar
+ */
+export function getStartServerButton(window: Page): Locator {
+  return window
+    .locator(".dome-xToolBar")
+    .getByRole("button", { name: "Start the server", exact: true });
+}
+
+/**
+ * Locator to select the Shut Down button in the top button bar
+ */
+export function getShutDownServerButton(window: Page): Locator {
+  return window.locator(".dome-xToolBar").getByTitle("Shut down the server");
+}
+
+/**
+ * Locator to select the Console View
+ */
+export function getConsoleView(window: Page): Locator {
+  return window.locator(".CodeMirror");
+}
+
+/**
+ * Locator to select the Functions side bar when loading a file
+ */
+export function getFunctionsSideBar(window: Page): Locator {
+  return window.locator(".dome-xSideBar").first();
+}
+
+export function getServerStatusLabel(window: Page): Locator {
+  return window.getByTitle("Server is running");
+}
diff --git a/ivette/tests/monkey/monkey-testing.spec.ts b/ivette/tests/monkey/monkey-testing.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0e5d7b9e3e5c19beaef0cad6553f43dae4bf3ea8
--- /dev/null
+++ b/ivette/tests/monkey/monkey-testing.spec.ts
@@ -0,0 +1,81 @@
+/* ************************************************************************ */
+/*                                                                          */
+/*   This file is part of Frama-C.                                          */
+/*                                                                          */
+/*   Copyright (C) 2007-2023                                                */
+/*     CEA (Commissariat à l'énergie atomique et aux énergies               */
+/*          alternatives)                                                   */
+/*                                                                          */
+/*   you can redistribute it and/or modify it under the terms of the GNU    */
+/*   Lesser General Public License as published by the Free Software        */
+/*   Foundation, version 2.1.                                               */
+/*                                                                          */
+/*   It is distributed in the hope that it will be useful,                  */
+/*   but WITHOUT ANY WARRANTY; without even the implied warranty of         */
+/*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
+/*   GNU Lesser General Public License for more details.                    */
+/*                                                                          */
+/*   See the GNU Lesser General Public License version 2.1                  */
+/*   for more details (enclosed in the file licenses/LGPLv2.1).             */
+/*                                                                          */
+/* ************************************************************************ */
+
+import { test } from "@playwright/test";
+import * as e2eService from "../libs/e2eService";
+
+/* eslint-disable  @typescript-eslint/no-explicit-any */
+let gremlins: any;
+
+test("run gremlins.js", async () => {
+  test.slow(); // long timeout for a very slow test.
+
+  const launchAppResult = await e2eService.launchApp(
+    e2eService.argsLaunchWithTestFile,
+  );
+  const electronApp = launchAppResult.app;
+  const window = launchAppResult.page;
+
+  // await window.pause()
+
+  // Load gremlins.js script
+  await window.addScriptTag(
+    { path: "./node_modules/gremlins.js/dist/gremlins.min.js", }
+  );
+
+  // Launch gremlins.js with default settings
+  // await window.evaluate(() => gremlins.createHorde().unleash());
+
+  // Launch gremlins.js with custom settings
+  // See https://github.com/marmelab/gremlins.js for more info
+
+  await window.evaluate(async () => {
+    await gremlins
+      .createHorde({
+        species: [
+          gremlins.species.clicker(), // clicks anywhere on the visible area of the document
+          gremlins.species.toucher(), // touches anywhere on the visible area of the document
+          gremlins.species.scroller(), // scrolls the viewport to reveal another part of the document
+          gremlins.species.typer(), // types keys on the keyboard
+          gremlins.species.formFiller(), // fills forms by entering data, selecting options, clicking checkboxes, etc
+        ],
+        mogwais: [
+          gremlins.mogwais.alert(), // prevents calls to alert() from blocking the test
+          gremlins.mogwais.fps(), // logs the number of frames per seconds (FPS) of the browser
+        ],
+        strategies: [
+          gremlins.strategies.distribution({
+            distribution: [0.3, 0.3, 0.3, 0.1, 0.1], // the first three gremlins have more chances to be executed than the last
+            delay: 10, // wait 10 ms between each action
+          }),
+        ],
+        randomizer: new gremlins.Chance(1234), // if you want the attack to be repeatable, you need to seed the random number generator
+      })
+      .unleash();
+  });
+
+  // Could be useful if you want to review the logs
+  // await window.pause()
+
+  // Exit app.
+  await electronApp.close();
+});
diff --git a/ivette/tests/settings.json b/ivette/tests/settings.json
new file mode 100644
index 0000000000000000000000000000000000000000..746bf14e7edaad3df59e5cf9cfedb4754369991a
--- /dev/null
+++ b/ivette/tests/settings.json
@@ -0,0 +1,38 @@
+{
+    "frame": {
+        "x": 100,
+        "y": 100,
+        "width": 1900,
+        "height": 1060
+    },
+    "settings": {
+        "frama-c.labview.shape": {
+            "kind": "VBOX",
+            "content": [
+                {
+                    "kind": "HBOX",
+                    "content": [
+                        {
+                            "kind": "ITEM",
+                            "id": "frama-c.astview"
+                        },
+                        {
+                            "kind": "ITEM",
+                            "id": "frama-c.sourcecode"
+                        }
+                    ]
+                },
+                {
+                    "kind": "ITEM",
+                    "id": "frama-c.astinfo"
+                }
+            ]
+        },
+        "frama-c.labview.panel.views.current": "builtin.views.source"
+    },
+    "storage": {
+        "Controller.history": [
+        ]
+    },
+    "devtools": false
+}
diff --git a/ivette/tsconfig.json b/ivette/tsconfig.json
index 5674a51edb47c9a247465452802fe6ebbc8c1350..0516d57b747b191ed288c55fa69ad7fac3feb49a 100644
--- a/ivette/tsconfig.json
+++ b/ivette/tsconfig.json
@@ -80,7 +80,8 @@
   },
   "include": [
     "src/**/*",
-    "api/**/*"
+    "api/**/*",
+    "tests/**/*",
   ],
   "exclude": [
     "node_modules",
diff --git a/ivette/yarn.lock b/ivette/yarn.lock
index 22ba43191184c39b0b20f9967f2f8123539d8b29..21b0736040dc934879e1b6505aa4ad64256ccc6a 100644
--- a/ivette/yarn.lock
+++ b/ivette/yarn.lock
@@ -2039,6 +2039,16 @@
     "@nodelib/fs.scandir" "2.1.5"
     fastq "^1.6.0"
 
+"@playwright/test@^1.36.0":
+  version "1.36.0"
+  resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.36.0.tgz#df2c0b09bbd27016adf1892b0c3502c4ce88d307"
+  integrity sha512-yN+fvMYtiyLFDCQos+lWzoX4XW3DNuaxjBu68G0lkgLgC6BP+m/iTxJQoSicz/x2G5EsrqlZTqTIP9sTgLQerg==
+  dependencies:
+    "@types/node" "*"
+    playwright-core "1.36.0"
+  optionalDependencies:
+    fsevents "2.3.2"
+
 "@popperjs/core@^2.0.0":
   version "2.11.0"
   resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.0.tgz#6734f8ebc106a0860dff7f92bf90df193f0935d7"
@@ -5382,6 +5392,11 @@ fs.realpath@^1.0.0:
   resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
   integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
 
+fsevents@2.3.2, fsevents@~2.3.2:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
+  integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
+
 fsevents@^1.2.7:
   version "1.2.13"
   resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38"
@@ -5390,11 +5405,6 @@ fsevents@^1.2.7:
     bindings "^1.5.0"
     nan "^2.12.1"
 
-fsevents@~2.3.2:
-  version "2.3.2"
-  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
-  integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
-
 function-bind@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@@ -7727,6 +7737,11 @@ pkg-dir@^4.1.0:
   dependencies:
     find-up "^4.0.0"
 
+playwright-core@1.36.0:
+  version "1.36.0"
+  resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.36.0.tgz#35d1ed5f364a31e58bc8f06688ab02d538b96eb6"
+  integrity sha512-7RTr8P6YJPAqB+8j5ATGHqD6LvLLM39sYVNsslh78g8QeLcBs5750c6+msjrHUwwGt+kEbczBj1XB22WMwn+WA==
+
 plist@^3.0.4:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.4.tgz#a62df837e3aed2bb3b735899d510c4f186019cbe"