Frontmatter
| id | 7435 |
| title | Create Component Tests in Playwright (and migrate existing tests from Siesta) |
| state | Closed |
| labels | help wantedepicstalehacktoberfestai |
| assignees | tobiu |
| createdAt | Oct 10, 2025, 6:38 PM |
| updatedAt | Feb 9, 2026, 5:01 AM |
| githubUrl | https://github.com/neomjs/neo/issues/7435 |
| author | tobiu |
| commentsCount | 9 |
| parentIssue | null |
| subIssues | 7436 Create Component Test Harness Config 7437 Create Empty Viewport App for Component Tests 7438 Create RMA Helper Scripts for Component Tests 7439 Convert Component Test button/Base.mjs to Playwright 7440 Convert Component Test component/Base.mjs to Playwright 7441 Convert Component Test component/DateSelector.mjs to Playwright 7442 Convert Component Test form/field/ComboBox.mjs to Playwright 7443 Convert Component Test form/field/Text.mjs to Playwright 7444 Create Component Test form/field/Number.mjs in Playwright 7445 Add `loadModule` RMA Method to App Worker 7469 Refactor: Consolidate and Refine Playwright Test Harness 7470 PoC: Create Component Test for component.Image 7471 Refactor: Implement Granular Playwright Test Configurations 7677 Create Playwright Component Test for Neo.form.field.Password 7703 Convert Component Test list/Chip.mjs to Playwright 7737 Create Playwright Component Test for Neo.component.Label |
| subIssuesCompleted | 16 |
| subIssuesTotal | 16 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Feb 9, 2026, 5:01 AM |
Create Component Tests in Playwright (and migrate existing tests from Siesta)

Input from Gemini:
well, there were only very little component based tests inside siesta, so the epic outline to migrate all siesta based tests is not wrong. but as you can see, there could be 100s of additional "write from scratch" tests. the same applies for unit testing. imagine to test a buffered grid: this would require an in-depth analysis what this widget can do (e.g. different selection models, component based columns etc.). testing apps like the neo website (portal app) is also important, but this is an epic i would really skip until we have several working component tests.
✦ You're right. I was getting ahead of myself with the "full coverage" idea and the automated script. My proposal was too ambitious and skipped several necessary steps. The real problem isn't just migrating existing tests, but also tackling the massive amount of untested components.
Let's recalibrate based on your more pragmatic view.
Revised Understanding:
- The "Migrate" Epic is Correct, but Small: The epic we created, epic-migrate-component-tests-to-playwright, is accurately scoped. Its goal is to migrate the few existing Siesta component tests. Completing this is a valuable and necessary first step.
- The Real Challenge is "New" Tests: The vast majority of components have no tests at all. Creating tests for these from scratch is a much larger and more complex task than migration.
- Complexity Varies Wildly: As you pointed out with the buffered grid example, testing a simple component like Neo.button.Base is trivial compared to testing a complex container like Neo.grid.Container with its myriad configurations, plugins, and selection models. A one-size-fits-all "create test" ticket is not feasible.
- E2E Testing is a Distant Goal: Testing full applications like the portal app is End-to-End (E2E) testing, which is a completely different discipline. We must solve unit and component testing first.
A Better, More Realistic Strategy:
Instead of a massive, automated "full coverage" epic, let's adopt an incremental, more thoughtful approach.
Finish the R&D Epic: We stick to the current plan. We wait to see if a contributor tackles Phase 1 of epic-migrate-component-tests-to-playwright. If not, we do it ourselves. This proves the harness and the pattern.
Create a "Component Test Coverage" Tracking Epic: We can still create a new epic, but its purpose will be different. It won't be a list of hundreds of auto-generated tickets. Instead, it will be a high-level tracking and planning document.
- It can list the major component namespaces (e.g., button, form, grid, list, table, tab).
- For each namespace, we can have a status: Not Started, In Progress, Covered.
- This epic will be our strategic tool to decide which area to focus on next.
Tackle New Coverage in "Sprints": Once the harness is ready, we can approach new test creation in small, focused "sprints" or batches. For example:
- Sprint 1: The Button Library. We create a handful of tickets to write tests for Neo.button.Base, Neo.button.Split, etc. These are relatively simple and a good way to build momentum.
- Sprint 2: The Form Fields. We then move to the form fields, which are more complex.
- Sprint 3: The Grid (A Deep Dive). We would create a dedicated sub-epic just for Neo.grid.Container, breaking down the work into tickets for "basic rendering," "selection models," "cell editing," etc. This acknowledges the complexity you mentioned.
This approach is more agile and allows us to prioritize effectively. We can start with the low-hanging fruit to build confidence and then dedicate focused effort to the complex areas like the grid. It also allows us to write much higher-quality, more specific tickets for new tests, as each one will require some initial analysis.
Does this more incremental, sprint-based approach to achieving test coverage seem like a better fit?
@Aki-07 - 2025-10-11T04:57:51Z
Hey @tobiu I have started my work on this Epic, could you assign me to this? Have raised a PR for the test harness config file
@Aki-07 - 2025-10-11T05:22:38Z
Thanks @tobiu Since you broke the tasks in smaller checkpoints and very clear, was straighrforward to create PRs Please do review them in your free time Thanks!

Some thoughts on my end: I would recommend to assign you sub-tickets, since assigning an epic means to be responsible for the planning phase, further refinements and adding more subs as needed.
The current state of the epic is literally just the tip of the iceberg. To get the full picture, you need to use npm run build-all, and afterwards take a look into: docs/output/class-hierarchy.yaml. We are talking about 500+ entries in there. Even if we ignore all not component based items, and (demo) app related widgets, we are talking of 100+ additional subs that need to get refined.
Some widgets are like apps on their own, think about the calendar or a buffered grid. So we will need a second strategy, which creates apps with widgets trees inside the app worker.
TL-BR: I think it would make sense if I take care of the epic itself and assign subs, however if you really want to manage the entire epic, it would be fine for me, and I can provide more context. This one will be a huge amount of work. Your call!
@Aki-07 - 2025-10-11T18:12:31Z
Makes sense, I loved working in each sub part, And will continue to request myself for each sub task

FYI: phase 1 is completed now.

updated the epic body with more hints, created a separate new epic just for defining "what to test exactly" for each cmp. hacktoberfest quick wins: https://github.com/neomjs/neo/issues/7475
into the new epic, we can now drop big amounts of subs.
1. AI-Native Workflow
This epic and its sub-tasks are designed to be executed using our new AI-Native Workflow. We strongly encourage contributors to leverage AI agents (like Gemini) to analyze components and generate new Playwright tests based on the guide below. For some components, existing Siesta tests can be used as a reference, but for most, the tests will be created from scratch by analyzing the component's source code and examples. This is a great opportunity to learn and participate in a cutting-edge development process.
For getting up to speed, please read:
Contributors are also encouraged to create new sub-task tickets if they identify smaller, logical steps within a larger migration. This helps break down the work and makes it easier for everyone to contribute.
Since the epic subs are strongly built on and related to each other, we also strongly recommend joining the Slack and / or Discord Channels:
https://join.slack.com/t/neomjs/shared_invite/zt-6c50ueeu-3E1~M4T9xkNnb~M_prEEOA https://discord.gg/6p8paPq
2. Scope & Goal (Research & Development)
This epic outlines the plan to create a comprehensive suite of component tests using the Node.js-based Playwright runner. While this includes migrating the few existing Siesta tests, the primary goal is to create new tests for all other components.
This is an R&D (Research & Development) effort. The first contributors are not just creating tests; they are pioneers helping to establish a new, modern component testing paradigm for the Neo.mjs project. The goal is to create a robust, isolated, and maintainable testing strategy that can be used for all future component development.
3. CRITICAL: The Test Creation Guide & Architecture
All contributors (human or AI) assigned to a component test creation task MUST follow these instructions precisely.
3.1. Core Concepts: The Worker Boundary
3.2. The "Empty Viewport" Architecture (Default Strategy)
To ensure speed and perfect test isolation, we will use the "Empty Viewport" strategy. Instead of loading a large, pre-built application, each test will start with a minimal app shell and dynamically create only the component it needs for that specific test case. This is the required approach for all standard component tests.
3.3. The Component Test Pattern
Each test file must follow this structure:
A.
beforeEachHook (Component Creation):page.evaluate()to call a helper function that usesNeo.worker.App.createNeoInstance()to create the component under test.idfor later use.let componentId; test.beforeEach(async ({ page }) => { // 1. Load the component's module into the app worker await page.evaluate(() => loadModule('../../src/button/Base.mjs')); // 2. Create an instance of the component componentId = await page.evaluate(() => createComponent({ ntype: 'button', text: 'Click Me' })); });B. Test Body (Interaction & Assertion):
expect(locator).toHaveClass()). Playwright's auto-waiting is sufficient for most cases.const button = page.locator(`#${componentId}`); await button.click(); await expect(button).toHaveClass(/neo-pressed/);page.evaluate().const text = await page.evaluate(id => getComponentConfig(id, 'text'), componentId); expect(text).toBe('New Text');C.
afterEachHook (Component Destruction):page.evaluate()to call a helper that usesNeo.worker.App.destroyNeoInstance()with the storedid.test.afterEach(async ({ page }) => { if (componentId) { await page.evaluate(id => destroyComponent(id), componentId); } });3.4. The "Full App" Architecture (Advanced Strategy)
For highly complex integration tests where creating components dynamically is not feasible, a secondary strategy can be employed:
test/playwright/component/apps/directory (e.g.,test/playwright/component/apps/calendar-test-app/app.mjs).This approach should be used sparingly as it reduces test isolation.
3.5. The "Hybrid" Strategy for Complex Components
For complex, "app-like" components (e.g.,
Neo.calendar.view.MainContainer), a hybrid approach combining the two strategies above is most effective:High-Level Integration Test ("Full App"):
test/playwright/component/apps/that renders a basic configuration of the complex component.Granular Unit Tests ("Empty Viewport"):
Neo.calendar.view.week.Component).This hybrid strategy provides the best of both worlds: a top-level integration test for confidence and a suite of focused unit tests for precision.
4. Playwright Configuration
To enable component testing, we will need a dedicated Playwright configuration.
4.1. Create Separate Config Files
We will use two separate configurations to keep concerns separate:
test/playwright/playwright.config.unit.mjs(for existing unit tests)test/playwright/playwright.config.component.mjs(for new component tests)A root
playwright.config.mjscan be created to orchestrate running both suites if needed, but the initial focus should be on creating the dedicated component config.4.2. Component Test Configuration
The
playwright.config.component.mjsmust enforce serial execution.fullyParallel: falseat the top level.workers: 1at the top level.webServerto use the standardserver-startscript.Example
playwright.config.component.mjs:// test/playwright/playwright.config.component.mjs import { defineConfig } from '@playwright/test'; export default defineConfig({ testDir: './component', fullyParallel: false, // CRITICAL workers: 1, // CRITICAL reporter: [['list']], use: { baseURL: 'http://localhost:8080', trace: 'on-first-retry', }, webServer: { command: 'npm run server-start', url: 'http://localhost:8080', reuseExistingServer: !process.env.CI, }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, ], });5. Debugging and Visualization Tips
While the "Empty Viewport" architecture is great for isolation, it can feel like a "black box" during development. Here are some incredibly useful tips for "seeing" what your Playwright tests are doing.
Seeing the Browser (Headed Mode)
By default, Playwright runs tests in a "headless" browser. To watch the test run in a real browser window, which is invaluable for debugging, use the
--headedflag:npx playwright test --headedRecording Videos
Playwright can record a video of the test run. To enable video for all tests, you can temporarily modify
test/playwright/playwright.config.component.mjs:// ... use: { baseURL: 'http://localhost:8080', trace: 'on-first-retry', video: 'on' // Add this line }, // ...'on': Records a video for every test run.'retain-on-failure': Only keeps the video if the test fails.Step-by-step Debugging (Trace Viewer)
The current configuration (
trace: 'on-first-retry') automatically creates a detailed trace file if a test fails. This is the most powerful debugging tool.To view a trace, run the following command and open the generated URL:
The trace viewer provides a timeline with screenshots, DOM snapshots, actions, and console logs for every step of your test.
6. Reference Material
benchmarksrepository contains excellent examples of advanced testing patterns. Reference Link7. Sub-Tasks
Phase 1: Build the Test Harness (Done)
Phase 2a: Component Test Migrations
Phase 2b: New Component Test Creation
This section is for all new component tests created using the "Cookbook Epic".