or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.mdinteraction-testing.mdlifecycle-testing.mdtest-generation.mdtesting-utilities.mdvisual-testing.md
tile.json

test-generation.mddocs/

Automated Test Generation

Automatic generation of comprehensive test cases for deck.gl layers based on layer properties, default values, and prop types. Creates systematic tests for property validation, data formats, and accessor functions.

Capabilities

Test Case Generation

Primary function for generating exhaustive test cases from layer configuration.

/**
 * Automatically generate comprehensive test cases for a layer
 * @param opts - Configuration for test generation
 * @returns Array of generated LayerTestCase objects
 */
function generateLayerTests<LayerT extends Layer>(opts: {
  /** The layer class to generate tests for */
  Layer: LayerClass<LayerT>;
  /** Override default props during the test (prevents conflicts with generated tests) */
  sampleProps?: Partial<LayerT['props']>;
  /** Custom assertion function (default: throws Error on false condition) */
  assert?: (condition: any, comment: string) => void;
  /** Called before each generated test case update */
  onBeforeUpdate?: LayerTestCase<LayerT>['onBeforeUpdate'];
  /** Called after each generated test case update */
  onAfterUpdate?: LayerTestCase<LayerT>['onAfterUpdate'];
  /** Test typical assumptions after layer updates (default: true) */
  runDefaultAsserts?: boolean;
}): LayerTestCase<LayerT>[];

Usage Examples:

import { generateLayerTests, testLayer } from "@deck.gl/test-utils";
import { ScatterplotLayer } from "@deck.gl/layers";

// Basic test generation
const testCases = generateLayerTests({
  Layer: ScatterplotLayer,
  sampleProps: {
    data: [
      { position: [0, 0], color: [255, 0, 0], size: 10 },
      { position: [1, 1], color: [0, 255, 0], size: 20 }
    ],
    getPosition: d => d.position,
    getFillColor: d => d.color,
    getRadius: d => d.size
  }
});

// Run the generated tests
testLayer({
  Layer: ScatterplotLayer,
  testCases
});

// Custom assertion and callbacks
const customTests = generateLayerTests({
  Layer: ScatterplotLayer,
  sampleProps: {
    data: [{ position: [0, 0] }],
    getPosition: d => d.position
  },
  assert: (condition, message) => {
    if (!condition) {
      console.error('Test failed:', message);
      throw new Error(message);
    }
  },
  onAfterUpdate: ({ layer, testCase }) => {
    console.log(`Completed test: ${testCase.title}`);
    console.log(`Layer has ${layer.getModels().length} models`);
  },
  runDefaultAsserts: true
});

Generated Test Categories

The generateLayerTests function creates several categories of test cases:

Core Layer Tests

Always generated for every layer:

  1. "Empty props" - Tests layer initialization with no props
  2. "Null data" - Tests layer behavior with null data
  3. "Sample data" - Tests layer with provided sample props

Property-Based Tests

Generated based on layer's defaultProps and propTypes:

Boolean Properties

Tests toggling boolean values from their defaults:

// If defaultProps.visible = true, generates:
{
  title: "LayerName#visible: false", 
  props: { visible: false }
}

Number Properties

Tests boundary values and variations:

// If prop has max/min constraints:
{ title: "LayerName#opacity: 1", props: { opacity: 1 } }  // max value
{ title: "LayerName#opacity: 0", props: { opacity: 0 } }  // min value

// Otherwise tests increment:
{ title: "LayerName#radiusScale: 2", props: { radiusScale: 2 } }  // default + 1

Accessor Properties

Tests both constant values and function accessors:

// Tests function accessor with call tracking:
{
  title: "LayerName#getPosition: () => [0, 0]",
  props: { 
    getPosition: () => [0, 0],
    updateTriggers: { getPosition: 'function' }
  },
  onBeforeUpdate: () => { /* reset call count */ },
  onAfterUpdate: () => { /* assert function was called */ }
}

// Tests updateTrigger changes:
{
  title: "LayerName#getPosition: updateTrigger", 
  updateProps: {
    updateTriggers: { getPosition: 'function+trigger' }
  }
}

Data Format Tests

Generated when sampleProps.data is an array:

  1. "Partial update" - Tests differential data updates with _dataDiff
  2. "Generic iterable data" - Tests with Set instead of Array
  3. "Non-iterable data" - Tests with object containing length property
// Example generated data format tests:
[
  {
    title: "LayerName#Partial update",
    updateProps: {
      data: [...originalData],
      _dataDiff: () => [{ startRow: 0, endRow: 2 }]
    }
  },
  {
    title: "LayerName#Generic iterable data", 
    updateProps: {
      data: new Set(originalData),
      _dataDiff: null
    }
  },
  {
    title: "LayerName#non-iterable data",
    updateProps: {
      data: { length: originalData.length },
      // Accessor functions adapted for indexed access
      getPosition: (_, info) => sampleProps.getPosition(originalData[info.index], info)
    }
  }
]

Default Assertions

When runDefaultAsserts: true (default), generated tests include automatic validation:

Composite Layers

For layers with layer.isComposite === true:

  • Asserts that layers with data have sublayers: assert(params.subLayers.length, 'Layer should have sublayers')

Primitive Layers

For non-composite layers:

  • Asserts that layers have WebGL models: assert(params.layer.getModels().length, 'Layer should have models')

Integration with Manual Tests

Generated tests work seamlessly with manually written test cases:

import { generateLayerTests, testLayer } from "@deck.gl/test-utils";
import { MyCustomLayer } from "./my-custom-layer";

const generatedTests = generateLayerTests({
  Layer: MyCustomLayer,
  sampleProps: { /* ... */ }
});

const manualTests = [
  {
    title: "Custom edge case",
    props: { /* specific configuration */ },
    onAfterUpdate: ({ layer }) => {
      // Custom validation logic
    }
  }
];

testLayer({
  Layer: MyCustomLayer,
  testCases: [...generatedTests, ...manualTests]
});

Error Handling

The test generator includes error handling for layer construction:

  • Catches and reports constructor errors with context
  • Validates that the layer class has required properties (layerName)
  • Provides descriptive error messages for debugging

All generated test failures include the full test case title with layer name prefix for easy identification (e.g., "ScatterplotLayer#getRadius: () => 10").