DEV Community

Discussion on: Testing your Solid.js code with jest

Collapse
peerreynders profile image
peerreynders • Edited on

Thank You.

To wrap my head around createRoot I needed something much more basic.

// $ node index.mjs
//
// NOTE: in Node.js "solid-js" maps to 
// "./node_modules/solid-js/dist/server.js"
// which doesn't run Effects
//
import {
  createEffect,
  createSignal,
  createRoot,
} from './node_modules/solid-js/dist/solid.js';

const log = console.log;

function executor(resolve, _reject) {
  createRoot(withRxGraph);

  // ---
  function withRxGraph(dispose) {
    const [count, setCount] = createSignal(0);

    let result;
    createEffect(() => {
      log('running effect');
      result = count();
    });

    setTimeout(() => {
      log('incrementing');
      setCount((n) => n + 1);

      log('flushing');
      dispose();

      resolve(result);
    });

    log('end setup');
  }
}

new Promise(executor).then((n) => log('result', n));
Enter fullscreen mode Exit fullscreen mode

Leaving it here in case somebody else might find it useful.

// $ node index.mjs
//
// NOTE: in Node.js "solid-js" maps to "./node_modules/solid-js/dist/server.js"
// which doesn't run Effects
//
import {
  createEffect,
  createSignal,
  createRoot,
} from './node_modules/solid-js/dist/solid.js';

const log = console.log;

async function rootAndRun(timeoutMs, factory) {
  let disposeFn;
  let timeoutId;
  try {
    return await new Promise(executor);
  } finally {
    if (disposeFn) {
      log('dispose');
      disposeFn();
      disposeFn = undefined;
    }
    if (timeoutId) {
      clearTimeout(timeoutId);
      timeoutId = undefined;
    }
  }

  // ---
  function executor(resolve, reject) {
    createRoot((dispose) => {
      disposeFn = dispose;
      timeoutId = setTimeout(timeout, timeoutMs);
      // queueMicrotask/setTimeout allows `setup` to finish
      // before exercising the reactive graph with `run`
      const run = factory(done);
      if (typeof run === 'function') queueMicrotask(run);
    });

    // ---
    function timeout() {
      timeoutId = undefined;
      reject(new Error('Timed out'));
    }

    function done(data, err) {
      log('done');
      if (err != undefined) reject(err);
      else resolve(data);
    }
  }
}

function factory(done) {
  // `setup` immediately
  const [count, setCount] = createSignal(0);

  let result;
  createEffect(() => {
    log(typeof result === 'number' ? 'effect' : 'first effect');
    result = count();
  });

  log('end setup');

  // package `run` in a function
  return function run() {
    // now effects are synchronous
    setCount((n) => n + 1);
    log('past increment');
    done(result);
  };
}

try {
  const result = await rootAndRun(1000, factory);
  console.log(result);
} catch (err) {
  console.error('ERROR', err);
}
Enter fullscreen mode Exit fullscreen mode