Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ HTMLReport/preview.html ── reads session ── renders stats, charts, filte
| `manifest.json` | MV3 manifest. Permissions: `storage`, `tabs`, `activeTab`, `downloads`, `scripting`, `notifications` |
| `background.js` | Service worker (`type: module`). Owns the `Session`, routes messages, saves to storage, triggers downloads, shows notifications |
| `popup.html`, `js/popup.js` | Popup UI: annotation forms, counters, export/import/clear, open report |
| `tutorial.html`, `js/tutorial.js`, `css/tutorial.css` | Interactive tutorial (Driver.js tour). Opened by the popup on first use and by the **?** help button. See [Tutorial](#tutorial) |
| `lib/driverjs/` | Vendored Driver.js (pinned version in its `README.md`), loaded locally — never from a CDN |
| `js/content_script.js` | Crop-area selection on the page; hosts the annotation editor iframe |
| `js/annotation_editor.*` | Screenshot editor (arrow, rectangle, text, blur, undo). Talks to the content script via `postMessage` (`initAnnotationEditor`, `annotationComplete`, `annotationCancelled`) |
| `src/Session.js` | Session model: browser info, start time, `annotations[]` |
Expand Down Expand Up @@ -94,6 +96,20 @@ Content script also sends `selectionCancelled` (not handled by background).
- **Download Report** — single self-contained HTML, screenshots inlined as base64, must work offline.
- **Download Images** — ZIP (JSZip) of screenshots named by type + timestamp, plus `README.txt`. Only offered in `preview.html`; deliberately omitted from downloaded reports to avoid Windows security warnings.

## Tutorial

`tutorial.html` is a guided tour of every user-facing feature: types of annotation, add with / without screenshot, crop with description and blur, report, export / import, and the **?** help button. It is shown automatically the first time the popup opens (`tutorialSeen` flag in the popup's `localStorage`) and reopened from the **?** button in `popup.html`.

**Keep the tutorial in sync.** Whenever you add a user-facing feature or change an existing one (popup buttons or shortcuts, crop / editor tools, report, export / import, session behaviour), update the tutorial in the same change:

1. `js/tutorial.js` — add, edit or remove the step. Steps target `[data-tour="..."]` elements; step text is English.
2. `tutorial.html` — the popup mock mirrors the markup of `popup.html` (same classes and ids so `css/popUp.css` styles it); mirror UI changes there. Editor and report scenes are screenshots with transparent `.hotspot` boxes (percent positions) that Driver.js highlights.
3. `images/tutorial/editor.png`, `images/tutorial/report.png` — regenerate when the editor or report UI changes, and re-check the hotspot positions. Use fake data only: no real URLs, names or customer content in screenshots.
4. `test/e2e/tutorial.spec.js` — the tour test walks every step and requires each one to highlight an existing element, so a removed or renamed `data-tour` target fails it.
5. If the change is user-visible, also refresh the README screenshots in `screenshots/` and the feature list.

Rules for the tutorial code: no CDN and no remote code (the page makes no external requests; a test enforces it); keep the last step pointing at the help button; the mock is inert, so never load `js/popup.js` in `tutorial.html`.

## Testing

### Unit (Jest)
Expand All @@ -104,7 +120,8 @@ Content script also sends `selectionCancelled` (not handled by background).

### E2E (Playwright)

- Specs in `test/e2e/*.spec.js`: `smoke`, `basic-functionality`, `reports-export`, `crop-screenshot`, `annotation-editor`. Shared setup in `test/e2e/helpers/extension-helper.js`; fixture pages in `test/e2e/test-pages/` (served at `http://localhost:8000/test/e2e/test-pages`).
- Specs in `test/e2e/*.spec.js`: `smoke`, `basic-functionality`, `reports-export`, `crop-screenshot`, `annotation-editor`, `tutorial`. Shared setup in `test/e2e/helpers/extension-helper.js`; fixture pages in `test/e2e/test-pages/` (served at `http://localhost:8000/test/e2e/test-pages`).
- `openExtensionPopup` marks the tutorial as seen (sets `tutorialSeen` in the extension's `localStorage`) so the first-run tutorial tab does not open during specs. Pass `{ firstRun: true }` to test the first-run behaviour.
- Runs one worker, not parallel (extensions require a persistent Chromium context). Retries 2× on CI.
- `npm run` scripts list spec files explicitly — **a new spec must be added to `test:e2e:all` and `test:e2e:ci` in `package.json`** or CI won't run it.
- Prefer role / label / test-id selectors over CSS paths; use Playwright's auto-waiting assertions, never fixed sleeps.
Expand Down Expand Up @@ -139,13 +156,13 @@ If your agent supports these, use them:

## Gotchas

- `genetareZip.ps1` (filename typo is real) packages an **allowlist** of runtime files (`manifest.json`, `background.js`, `popup.html`, `css`, `HTMLReport`, `icons`, `images`, `js`, `lib`, `src`). A new top-level runtime file or folder must be added to `$include`, or it will be missing from the store package.
- `README.md` still claims `ExportSessionCSV.test.js` is broken — it now passes.
- `genetareZip.ps1` (filename typo is real) packages an **allowlist** of runtime files (`manifest.json`, `background.js`, `popup.html`, `tutorial.html`, `css`, `HTMLReport`, `icons`, `images`, `js`, `lib`, `src`). A new top-level runtime file or folder must be added to `$include`, or it will be missing from the store package.

## Definition of done

1. `npm test` passes.
2. Relevant E2E specs pass (`npm run test:e2e:all` for UI / message-flow changes).
3. New `chrome.*` calls are mocked in `jest.setup.js`; new specs are wired into `package.json`.
4. Extension reloaded and the change checked manually in Chrome when it affects UI.
5. This file updated if architecture, commands or conventions changed.
5. The tutorial (`js/tutorial.js`, `tutorial.html`, images) and README features / screenshots updated if the change is user-visible.
6. This file updated if architecture, commands or conventions changed.
88 changes: 51 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,62 +1,76 @@
# A Chrome Extension for Exploratory Testing

A Chrome extension designed for making web exploratory testing easier
A Chrome extension designed for making web exploratory testing easier. Record what you find while you explore a web page, with the URL and a screenshot attached, and review the whole session in a report.

**Features**
Install from [Chrome Store](https://chrome.google.com/webstore/detail/exploratory-testing-chrom/khigmghadjljgjpamimgjjmpmlbgmekj)

- Report bugs, ideas, notes and questions easily
- Take screenshots during the session. Keep focused
- URL will be tracked automatically
- See session results in a report
- Export and import sessions
- Export session to JSON, CSV or HTML
## Features

- **Four annotation types**: Bugs, Notes, Questions and Ideas, each with a counter in the popup.
- **Screenshots without changing context**: add an annotation with no screenshot, with a screenshot of the visible tab, or with a cropped area of the page.
- **Annotation editor for cropped screenshots**: arrow, rectangle, text and **blur** (to hide sensitive data), with undo and keyboard shortcuts.
- **Automatic tracking**: the URL, time and browser information are saved with every annotation.
- **Session report**: statistics per type, distribution chart, filter by type, annotations table and delete.
- **Download the report** as a standalone HTML file that works offline, or all screenshots as a ZIP.
- **Export and import sessions**: export to JSON or CSV, and import a JSON session to continue it later.
- **Interactive tutorial**: a guided tour that opens the first time you use the extension and can be reopened from the **?** button.
- **Keyboard shortcuts** in the description box: `Ctrl + Enter` adds the annotation, `Shift + Enter` adds it with a screenshot.

Install from [Chrome Store](https://chrome.google.com/webstore/detail/exploratory-testing-chrom/khigmghadjljgjpamimgjjmpmlbgmekj)
## Screenshots

**Annotate any thought while you test and take screenshots without changing context**

**Annotate any thought while you test easily and take screenshots without changing context**
<img src="./screenshots/popup.png" width="400" alt="Extension popup with a Bug form open">

<img src="./screenshots/new_Annotation.PNG" width="440">
**Crop, annotate and blur the screenshot**

<img src="./screenshots/editor.png" width="800" alt="Annotation editor with a rectangle, an arrow and a blurred area">

**View session results in a report**

<img src="./screenshots/report.PNG" width="800">
<img src="./screenshots/report.png" width="800" alt="Session report with statistics, chart and annotations table">

**Learn the features with the built-in tutorial**

<img src="./screenshots/tutorial.png" width="800" alt="Interactive tutorial highlighting the crop button">

## Tutorial

The extension opens an interactive tutorial the first time you open its popup. It covers adding annotations (with and without screenshots), cropping with description and blur, viewing the report, and exporting or importing a session. To see it again, click the **?** button at the top right of the popup.

The tour is built with [Driver.js](https://driverjs.com/), bundled in `lib/driverjs/` (no CDN). The page is `tutorial.html`, with the steps in `js/tutorial.js`.

## Development and Testing

This section provides instructions for setting up the project locally for development and running tests.
Plain JavaScript, no bundler and no runtime npm dependencies: the repository root is the extension. [AGENTS.md](./AGENTS.md) has the architecture, conventions and the full list of commands.

### Project Setup

1. **Prerequisites**: Ensure you have [Node.js](https://nodejs.org/) installed (which includes npm).
2. **Clone the Repository**:
```bash
git clone https://github.com/your-username/your-repo-name.git
cd your-repo-name
```
*(Using a common placeholder format for the repo URL. The user can update this if they wish).*
3. **Install Dependencies**:
```bash
npm install
```
This will install Jest, Babel, and other necessary development dependencies as defined in `package.json`.
1. **Prerequisites**: [Node.js](https://nodejs.org/) 20 (includes npm).
2. **Clone the repository**:
```bash
git clone https://github.com/morvader/ExploratoryTestingChromeExtension.git
cd ExploratoryTestingChromeExtension
```
3. **Install development dependencies** (Jest, Playwright):
```bash
npm install
npx playwright install chromium
```
4. **Load the extension**: open `chrome://extensions`, enable *Developer mode*, choose *Load unpacked* and select the repository folder.

### Running Tests

The project uses [Jest](https://jestjs.io/) for unit testing.

1. **Execute Tests**:
```bash
npm test
```
Alternatively, you can run Jest directly:
```bash
npx jest
```
2. **Test Results**: Most tests should pass.
* **Known Issue**: The test suite for `test/spec/ExportSessionCSV.test.js` is currently non-functional due to a syntax error that occurred during the migration to Jest and could not be resolved with available tools. This specific suite will fail or be skipped. All other test suites should pass.
| Command | What it runs |
|---------|--------------|
| `npm test` | Jest unit tests (`test/spec/`) |
| `npm run test:e2e` | Playwright smoke and basic functionality |
| `npm run test:e2e:all` | Full Playwright suite (same as CI) |
| `npm run test:all` | Unit tests plus the full E2E suite |

### Release package

On Windows, `.\genetareZip.ps1` creates `ETExtension-<timestamp>.zip` with the runtime files only, ready to upload to the Chrome Web Store.

---
_PS: I'm not a web designer, so any help with web design or UX will be appreciated._
Expand Down
26 changes: 26 additions & 0 deletions css/popUp.css
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,32 @@ body {
border-bottom: none;
}

.header-with-help {
display: flex;
align-items: center;
justify-content: space-between;
padding-right: 8px;
}

.help-btn {
width: 26px;
height: 26px;
padding: 0;
border: 1.5px solid var(--color-primary);
border-radius: 50%;
background: var(--color-surface);
color: var(--color-primary);
font-weight: 700;
line-height: 1;
cursor: pointer;
transition: all var(--transition);
}

.help-btn:hover {
background: var(--color-primary);
color: #ffffff;
}

.card-header h5 {
font-size: 1rem;
font-weight: 600;
Expand Down
130 changes: 130 additions & 0 deletions css/tutorial.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/* Tutorial page. Loaded after popUp.css, which also styles the popup mock. */

/* popUp.css limits the body to popup width; the tutorial page needs the full window. */
body.tutorial {
min-width: 0;
max-width: none;
background-color: var(--color-bg);
}

.tutorial-header {
text-align: center;
padding: 40px 16px 24px;
background: linear-gradient(135deg, var(--color-primary), #8b5cf6);
color: #ffffff;
}

.tutorial-header h1 {
font-size: 1.8rem;
font-weight: 700;
margin-bottom: 8px;
}

.tutorial-header p {
margin-bottom: 16px;
opacity: 0.9;
}

.tutorial-header .btn-primary {
background-color: #ffffff;
border-color: #ffffff;
color: var(--color-primary-dark);
border-radius: var(--radius-md);
padding: 8px 20px;
font-weight: 600;
}

.tutorial-main {
max-width: 1000px;
margin: 0 auto;
padding: 24px 16px 64px;
}

.scene {
margin-bottom: 48px;
}

.scene h2 {
font-size: 1.3rem;
font-weight: 700;
margin-bottom: 4px;
}

.scene-caption {
color: var(--color-text-secondary);
margin-bottom: 16px;
}

/* Popup mock: same width as the real popup, inert. */
.popup-mock {
width: 400px;
max-width: 100%;
margin: 0 auto;
padding: 8px;
background: #ffffff;
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-md);
pointer-events: none;
user-select: none;
}

.popup-mock #resetBtn {
margin-right: 0;
}

.popup-mock .session-buttons {
display: inline-flex;
gap: 6px;
}

/* Screenshots with transparent hotspots that Driver.js can highlight. */
.shot {
position: relative;
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-md);
overflow: hidden;
background: #ffffff;
}

.shot img {
display: block;
width: 100%;
height: auto;
}

.hotspot {
position: absolute;
display: block;
pointer-events: none;
}

/* Driver.js popover tweaks to match the extension look. */
.driver-popover.et-tour {
font-family: var(--font-sans);
border-radius: var(--radius-md);
max-width: 340px;
}

.driver-popover.et-tour .driver-popover-title {
font-size: 1.05rem;
font-weight: 700;
}

.driver-popover.et-tour .driver-popover-description {
line-height: 1.45;
}

.driver-popover.et-tour .driver-popover-description kbd {
background: #f1f5f9;
border: 1px solid var(--color-border);
border-radius: 4px;
color: var(--color-text);
padding: 0 4px;
}

.driver-popover.et-tour .driver-popover-next-btn,
.driver-popover.et-tour .driver-popover-prev-btn {
border-radius: var(--radius-sm);
}
1 change: 1 addition & 0 deletions genetareZip.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ $include = @(
"manifest.json",
"background.js",
"popup.html",
"tutorial.html",
"css",
"HTMLReport",
"icons",
Expand Down
Binary file added images/tutorial/editor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/tutorial/report.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions js/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,27 @@ window.onload = function () {
})
}

const TUTORIAL_SEEN_KEY = 'tutorialSeen';

function openTutorial() {
chrome.tabs.create({ url: chrome.runtime.getURL('tutorial.html'), active: true });
}

// Opens the tutorial the first time the popup is shown; the help button reopens it afterwards.
function tutorialListeners() {
$(document).on('click', '#helpBtn', openTutorial);

try {
if (localStorage.getItem(TUTORIAL_SEEN_KEY)) return;
localStorage.setItem(TUTORIAL_SEEN_KEY, '1');
} catch (e) {
return; // storage unavailable: skip the automatic tutorial rather than show it on every open
}
openTutorial();
}

function initElements() {
tutorialListeners();
annotationListeners();
exportListeners();
updateCounters();
Expand Down
Loading
Loading