From b0ca3ce3bb7162c90f8942607bb233c79041e635 Mon Sep 17 00:00:00 2001 From: Thomas Raffelsieper Date: Fri, 13 Feb 2026 06:11:58 +0100 Subject: [PATCH 01/33] refactor: modernize codebase, fix bugs, add E2E tests & Docker setup - Rewrite background.js with handler registry pattern (15 handlers) - Modernize popup.js with declarative state machine - Extract shared clipboard.js module - Fix P0 bugs: missing statusMessage keys, package.json main typo, stray backtick - Fix extension tab overwriting recordTab (pause/resume bug) - Update all deps: ESLint 9 (flat config), Mocha 10, Playwright 1.50, c8, Husky 9 - Modernize CI: GitHub Actions v4, Node 20 - Add theme.css design system with dark/light theme support - Add 23 Playwright E2E tests (record, scan, pause/resume, export, settings, xpath) - Add Docker E2E infrastructure (Dockerfile.test, docker-compose, Xvfb) - 64 unit tests + 23 E2E tests all passing --- .eslintrc.json | 23 - .github/workflows/on-push.yml | 15 +- .gitignore | 2 + Dockerfile.test | 17 + REFACTORING_PLAN.md | 203 + assets/options.css | 71 +- assets/style.css | 926 +-- assets/theme.css | 212 + docker-compose.test.yml | 10 + eslint.config.js | 71 + package-lock.json | 6849 +++++++------------- package.json | 47 +- playwright.config.js | 21 + script/generate-logos.js | 6 +- scripts/test-e2e-docker.sh | 5 + src/actions-view.html | 4 + src/actions-view.js | 5 +- src/background.js | 563 +- src/constants.js | 14 +- src/content.js | 4 +- src/intro.js | 22 +- src/logger.js | 3 +- src/options.html | 18 +- src/options.js | 13 +- src/popup.html | 60 +- src/popup.js | 427 +- src/translations.js | 46 +- test/e2e/actions-view.spec.js | 145 + test/e2e/clear-rerecord.spec.js | 68 + test/e2e/export-download.spec.js | 99 + test/e2e/fixtures/empty-page.html | 7 + test/e2e/fixtures/form-page.html | 38 + test/e2e/fixtures/links-page.html | 22 + test/e2e/pause-resume.spec.js | 72 + test/e2e/record-flow.spec.js | 133 + test/e2e/scan-flow.spec.js | 66 + test/e2e/settings.spec.js | 117 + test/e2e/setup.js | 121 + test/e2e/xpath-validation.spec.js | 68 + test/integration/extension_install_spec.js | 6 +- test/locator/scanner_spec.js | 2 +- test/locator/xpath-locator_spec.js | 2 +- test/options_spec.js | 2 +- test/setup.js | 2 +- test/translator/robot-translator_spec.js | 2 +- yarn.lock | 3927 ++++------- 46 files changed, 6085 insertions(+), 8471 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 Dockerfile.test create mode 100644 REFACTORING_PLAN.md create mode 100644 assets/theme.css create mode 100644 docker-compose.test.yml create mode 100644 eslint.config.js create mode 100644 playwright.config.js create mode 100755 scripts/test-e2e-docker.sh create mode 100644 test/e2e/actions-view.spec.js create mode 100644 test/e2e/clear-rerecord.spec.js create mode 100644 test/e2e/export-download.spec.js create mode 100644 test/e2e/fixtures/empty-page.html create mode 100644 test/e2e/fixtures/form-page.html create mode 100644 test/e2e/fixtures/links-page.html create mode 100644 test/e2e/pause-resume.spec.js create mode 100644 test/e2e/record-flow.spec.js create mode 100644 test/e2e/scan-flow.spec.js create mode 100644 test/e2e/settings.spec.js create mode 100644 test/e2e/setup.js create mode 100644 test/e2e/xpath-validation.spec.js diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index d092ad6..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "extends": ["airbnb-base", ".eslintrc-todo"], - "env": { - "mocha": true, - "browser": true - }, - "rules": { - "comma-dangle": ["error", "only-multiline"], - "max-len": ["error", {"code":120, "comments": 120}], - "no-template-curly-in-string": "off", - "no-plusplus": "off", - "guard-for-in": "off", - "prefer-destructuring": "off", - "no-else-return": ["warn", {"allowElseIf": true}], - "globals": { - "window": "readonly" - }, - "import/extensions": [ "always", - { "js": "always" } - ], - "import/prefer-default-export": "off" - } -} diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml index fe8b6c9..884f7dc 100644 --- a/.github/workflows/on-push.yml +++ b/.github/workflows/on-push.yml @@ -11,14 +11,9 @@ jobs: test: runs-on: ubuntu-latest steps: - - name: Start xvfb on Linux - if: matrix.os == 'ubuntu-latest' - run: | - export DISPLAY=:99.0 - Xvfb -ac :99 -screen 0 1280x1024x16 > /dev/null 2>&1 & - - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: 12 - - run: yarn - - run: xvfb-run --auto-servernum yarn test + node-version: 20 + - run: npm ci + - run: xvfb-run --auto-servernum npm test diff --git a/.gitignore b/.gitignore index 6f954df..1d56386 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ archive/ node_modules/ .nyc_output test-user-data-dir +test-results/ +test/e2e/.tmp-profile-*/ diff --git a/Dockerfile.test b/Dockerfile.test new file mode 100644 index 0000000..d2c9a84 --- /dev/null +++ b/Dockerfile.test @@ -0,0 +1,17 @@ +FROM mcr.microsoft.com/playwright:v1.58.0-noble + +RUN apt-get update && apt-get install -y --no-install-recommends \ + xvfb \ + x11-utils \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY package.json package-lock.json* ./ +RUN npm ci +COPY . . + +ENV DOCKER=1 +ENV DISPLAY=:99 +ENV PLAYWRIGHT_FORCE_TTY=0 + +CMD xvfb-run --auto-servernum --server-args="-screen 0 1280x720x24" npx playwright test test/e2e/ --reporter=list 2>&1 diff --git a/REFACTORING_PLAN.md b/REFACTORING_PLAN.md new file mode 100644 index 0000000..b72c1fa --- /dev/null +++ b/REFACTORING_PLAN.md @@ -0,0 +1,203 @@ +# Refactoring Plan — RobotFramework Recorder + +> Generated 2026-02-12. Based on full source analysis of all files in `src/`, `test/`, config, and assets. + +--- + +## 1. Code Quality Issues + +### 1.1 Dead Code +- **`src/popup.js:16-30`** — Commented-out Google Analytics block (`gaAccount`, `_gaq`). The `analytics()` function on line 32 is a no-op stub. Remove both entirely. +- **`src/popup.js:34`** — `analytics()` is called in 5 places but does nothing. Remove all call sites. +- **`src/content.js:8-17`** — Large commented-out `MutationObserver` block. Either implement or remove. +- **`src/background.js:8`** — `tab` is imported from constants but shadowed by the destructured `const [tab]` on line 72. The import is unused. +- **`src/background.js:7`** — `url` import is only used in the `info` operation (line 168) — consider inlining. +- **`src/background.js:14`** — `maxLength = 5000` is passed as the `length` parameter but `generateOutput` just uses it as a cap on list iteration. The name is misleading — it's max *actions*, not max *length*. +- **`src/background.js:4`** — `/* global instruction filename statusMessage url tab logo initializeTranslator */` lists globals that are now ES module imports. Remove the comment. +- **`src/popup.js:1`** — `/* global document chrome IntroTour t getCurrentLanguage setLanguage */` — `IntroTour` is loaded via ` - - - + + RobotFramework Recorder - Options + + + + + +
@@ -24,11 +28,13 @@

Language

Custom Locators

Add your own flavoured locators! Separate with a commas.
- + + + diff --git a/src/options.js b/src/options.js index d964e1f..955f2b7 100644 --- a/src/options.js +++ b/src/options.js @@ -1,11 +1,10 @@ -/* global document chrome t getCurrentLanguage setLanguage */ +import { t, getCurrentLanguage, setLanguage } from './translations.js'; -const host = chrome; -const storage = host.storage.local; +const storage = chrome.storage.local; let currentLanguage = 'en'; -function update() { +export function update() { const values = document.getElementById('custom-locators').value; const array = values ? values.split(',') : ['for', 'name', 'id', 'title', 'href', 'class']; storage.set({ locators: array }); @@ -33,23 +32,17 @@ async function changeLanguage(e) { } document.addEventListener('DOMContentLoaded', async () => { - // Load current language currentLanguage = await getCurrentLanguage(); const state = await storage.get({ locators: [] }); document.getElementById('custom-locators').value = state.locators.join(','); - // Update UI translations updateUITranslations(currentLanguage); - // Set language radio button document.getElementById(`lang_${currentLanguage}`).checked = true; document.getElementById('update').addEventListener('click', update); - // Language change event listener Array.from(document.getElementsByClassName('language-option')) .forEach(elem => elem.addEventListener('change', changeLanguage)); }); - -if (typeof exports !== 'undefined') exports.update = update; diff --git a/src/popup.html b/src/popup.html index 95220a5..8b12a72 100644 --- a/src/popup.html +++ b/src/popup.html @@ -1,47 +1,51 @@ - + - + RobotFramework Recorder - + + + + + - +
- - - - - - - - - -
+ + +
@@ -63,11 +67,11 @@

Target Library

Target RF Syntax

- +
- +
@@ -85,11 +89,11 @@

Language

Advanced settings

- +
- +
@@ -99,38 +103,36 @@

Advanced settings

-
+
- -
- -
-