Skip to content

[p5.js 2.0+ Bug Report]: Missing unit tests for src/core/States.js #8761

@harshiltewari2004

Description

@harshiltewari2004

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • WebGPU
  • p5.strands
  • Build process
  • Unit testing
  • Internationalization
  • Friendly errors
  • Other (specify if possible)

p5.js version

dev-2.0 branch(verified on commit e83e9d4)

Web browser and version

N/A — missing test coverage, not a runtime bug

Operating system

N/A — missing test coverage, not a runtime bug

Steps to reproduce this

This is a test-coverage gap I noticed while exploring the dev-2.0 codebase, not a runtime bug — so the standard reproduction steps don't apply.

Background

src/core/States.js defines the States class, which is the core state-diffing mechanism used by push() / pop() across the library. Despite its central role, it has no dedicated unit test file. Its methods (setValue, getDiff, getModified, applyDiff) are exercised only indirectly through other tests.

Proposed addition

I'd like to add a new file test/unit/core/States.js with direct tests for each method, plus one integration-style test covering the push/pop usage pattern.

import { States } from '../../../src/core/States.js';

suite('States', function () {
  test('initialises with provided state', function () {
    const s = new States({ fill: 'red', stroke: 'blue' });
    assert.equal(s.fill, 'red');
    assert.equal(s.stroke, 'blue');
  });

  test('setValue() updates the value', function () {
    const s = new States({ fill: 'red' });
    s.setValue('fill', 'green');
    assert.equal(s.fill, 'green');
  });

  test('setValue() records the original before first modification', function () {
    const s = new States({ fill: 'red' });
    s.setValue('fill', 'green');
    assert.equal(s.getModified().fill, 'red');
  });

  test('setValue() does not overwrite original on repeated calls', function () {
    const s = new States({ fill: 'red' });
    s.setValue('fill', 'green');
    s.setValue('fill', 'blue');
    assert.equal(s.getModified().fill, 'red');
  });

  test('getDiff() returns the modified map', function () {
    const s = new States({ fill: 'red' });
    s.setValue('fill', 'green');
    const diff = s.getDiff();
    assert.equal(diff.fill, 'red');
  });

  test('getDiff() clears #modified after returning', function () {
    const s = new States({ fill: 'red' });
    s.setValue('fill', 'green');
    s.getDiff();
    assert.deepEqual(s.getDiff(), {});
  });

  test('applyDiff() undoes current modifications and replaces #modified', function () {
    const s = new States({ fill: 'red' });
    s.setValue('fill', 'green');
    const outerModified = {};
    s.applyDiff(outerModified);
    assert.equal(s.fill, 'red');
    assert.deepEqual(s.getModified(), {});
  });

  test('applyDiff() with a non-empty prevModified replaces #modified', function () {
    const s = new States({ fill: 'red', stroke: 'black' });
    s.setValue('fill', 'green');
    const outerModified = { stroke: 'black' };
    s.applyDiff(outerModified);
    assert.equal(s.fill, 'red');
    assert.deepEqual(s.getModified(), { stroke: 'black' });
  });

  test('push/pop cycle: applyDiff restores prior state', function () {
    const s = new States({ fill: 'red' });
    const beforePush = s.getDiff();
    s.setValue('fill', 'green');
    assert.equal(s.fill, 'green');
    s.applyDiff(beforePush);
    assert.equal(s.fill, 'red');
    assert.deepEqual(s.getModified(), {});
  });
});

Side observation

While drafting these tests I noticed that applyDiff(prevModified) is somewhat misleadingly named — it doesn't apply the passed-in diff to the current state. It undoes the current modifications (writing the values stored in #modified back to this[key]) and then replaces #modified with the parameter. The parameter name prevModified reflects this — it's the previous #modified state to reinstall, consistent with pop semantics. This works correctly for its actual use case, but the method name took me a moment to parse against the implementation. Flagging only as an observation, not proposing a rename.

Notes

  • Verified on dev-2.0 HEAD (commit e83e9d4) — no existing test file at test/unit/core/States.js.
  • All test sketches above were traced against the actual implementation in src/core/States.js to ensure they match real behavior.
  • Happy to take this on if approved.

Metadata

Metadata

Type

No type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions