npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@memberjunction/react-test-harness

v5.41.0

Published

React component test harness for MemberJunction using Playwright

Readme

@memberjunction/react-test-harness

Automated test harness for MemberJunction interactive React components. Provides static analysis (linting) with 57 extensible rules, type inference, constraint validation, browser-based rendering via Playwright, and a CLI for running test suites.

Quick Start

Linting a Component

import { ComponentLinter } from '@memberjunction/react-test-harness';

const result = await ComponentLinter.lintComponent(
  code,           // JavaScript/JSX source
  'MyComponent',  // Component name
  componentSpec,  // ComponentSpec with metadata
  true,           // isRootComponent
);

if (!result.success) {
  for (const v of result.violations) {
    console.log(`[${v.severity}] ${v.rule}: ${v.message} (line ${v.line})`);
  }
}

Browser-Based Testing

import { ComponentRunner } from '@memberjunction/react-test-harness';

const runner = new ComponentRunner();
const result = await runner.executeComponent(componentSpec, {
  contextUser,
  props: { data: testData },
});

console.log('Rendered:', result.success);
console.log('Errors:', result.errors);

Connecting to an existing browser

By default the harness launches its own throwaway Chromium. You can instead attach to an already-running browser — useful for watching component runs in a browser you control, or for reusing a warm/remote browser (pool, Docker) instead of paying a cold launch each run.

// Attach to a real Chrome started with --remote-debugging-port=9222 (CDP)
const harness = new ReactTestHarness({ connect: 'http://localhost:9222' });

// Attach to a Playwright server started via chromium.launchServer() (ws endpoint)
const harness = new ReactTestHarness({ connect: 'ws://localhost:55001/<id>' });
  • Auto-detect: http(s):// endpoints use CDP (connectOverCDP); ws(s):// endpoints use a Playwright server (connect). A raw CDP websocket also starts with ws:// — pass connectType: 'cdp' to force CDP in that case.
  • Env-var fallback: set MJ_REACT_TEST_HARNESS_CONNECT to the endpoint instead of passing connect (so the mj-react-test CLI can attach without a new flag).
  • Session reuse: by default a fresh isolated context is created inside the attached browser. Set reuseExistingContext: true (or MJ_REACT_TEST_HARNESS_REUSE_CONTEXT=true) to reuse the browser's existing default context and share its cookies/auth/session. This breaks per-test isolation, so keep the default for parallel runs.
  • Lifecycle safety: when attached, harness.close() only closes the pages and contexts the harness created — it never closes a browser it did not launch, nor a reused/shared context. The external browser's lifecycle is the caller's.
  • headless is ignored when attaching (the external browser already decided).

Writing Custom Rules

Rules extend BaseLintRule and auto-register via @RegisterClass:

import { RegisterClass } from '@memberjunction/global';
import { BaseLintRule } from '@memberjunction/react-test-harness';

@RegisterClass(BaseLintRule, 'my-custom-rule')
export class MyCustomRule extends BaseLintRule {
  get Name() { return 'my-custom-rule'; }
  get AppliesTo(): 'all' | 'child' | 'root' { return 'all'; }

  Test(ast, componentName, componentSpec, options, typeContext) {
    const violations = [];
    // Babel AST traversal and validation logic
    return violations;
  }
}

External packages (e.g., Skip-Brain) can define custom rules — the linter discovers them automatically via MJGlobal's ClassFactory.

Testing

cd packages/React/test-harness

# Build (required before testing)
npm run build

# Run all 425 tests
npx vitest run

# Run with verbose output (see individual fixture results)
npx vitest run --reporter=verbose

# Watch mode
npx vitest

Database Connection (Optional)

Some rules validate against entity metadata from the database. Create .env:

DB_HOST=your-host
DB_DATABASE=your-db
DB_USERNAME=your-user
DB_PASSWORD=your-password
DB_PORT=1433
DB_TRUST_SERVER_CERTIFICATE=1

Without a database, DB-dependent fixtures still run but rules that need entity metadata emit low-severity warnings instead of violations.

Architecture

See LINTER-ARCHITECTURE.md for comprehensive documentation including:

  • How rules work and how to add new ones
  • Rule categories and what each validates
  • Type inference engine capabilities
  • Metadata fallback strategy
  • SQL dialect configuration
  • Test fixture organization

Lint Rules (57)

Data Access (5 rules)

  • runview-call-validation — RunView/RunViews call-site validation
  • runquery-call-validation — RunQuery call-site validation with parameter type checking
  • data-result-validation — RunView/RunQuery/Search result usage patterns
  • search-availability-checkutilities.search null guard
  • search-call-validation — Search/PreviewSearch parameter validation

Entity & Query Fields (4 rules)

  • entity-field-access-validation — Field access on RunView results (typos, case, type coercion)
  • query-result-field-access-validation — Field access on RunQuery results
  • chart-field-validation — Chart prop field references
  • datagrid-field-validation — Grid column field references

Runtime Constraints (8 rules)

  • no-import-statements, no-export-statements, no-require-statements
  • no-iife-wrapper, no-return-component, no-window-access
  • use-function-declaration, single-function-only

Component Structure (9 rules)

  • react-component-naming, component-name-mismatch, pass-standard-props
  • no-react-destructuring, no-data-prop, no-child-implementation
  • component-props-validation, child-component-prop-validation
  • component-usage-without-destructuring

Dependencies (7 rules)

  • component-not-in-dependencies, undefined-component-usage
  • unused-libraries, unused-component-dependencies
  • library-variable-names, dependency-shadowing, validate-component-references

Callbacks & Events (1 consolidated rule)

  • callback-event-validation — Method usage, parameter signatures, passthrough, event null-checks

Best Practices (8 rules)

  • prefer-async-await, prefer-jsx-syntax, react-hooks-rules
  • useeffect-unstable-dependencies, unsafe-array-operations, unsafe-formatting-methods
  • string-replace-all-occurrences, string-template-validation

Type Safety (2 rules)

  • type-inference-errors, type-mismatch-operation

Styles (1 consolidated rule)

  • styles-validation — Invalid path access, unsafe patterns

Utilities (3 rules)

  • utilities-api-validation, utilities-no-direct-instantiation, ai-tools-availability-check

State & Settings (5 rules)

  • saved-user-settings-pattern, noisy-settings-updates, prop-state-sync
  • property-name-consistency, server-reload-on-client-operation

Other (4 rules)

  • no-use-reducer, required-queries-not-called
  • undefined-jsx-component, no-child-implementation

Exports

// Core linting
export { ComponentLinter, LintResult, Violation } from './lib/component-linter';
export { BaseLintRule } from './lib/lint-rule';

// Test harness
export { ReactTestHarness, TestHarnessOptions } from './lib/test-harness';
export { ComponentRunner, ComponentExecutionOptions, ComponentExecutionResult } from './lib/component-runner';
export { BrowserManager, BrowserContextOptions } from './lib/browser-context';

// Utilities
export { LibraryLintCache, CompiledLibraryRules, CompiledValidator } from './lib/library-lint-cache';
export { ComponentSpec } from '@memberjunction/interactive-component-types';

License

ISC