Files
react/compiler/packages/sprout
Joe Savona 702aadd82b Fix to only add imports if we compiled something
We should only add imports if we actually compiled anything, this is what caused 
the internal issue despite the file in question not having any functions 
opted-in to compilation.
2023-11-07 16:22:03 -08:00
..

Sprout 🌱

React Forget test framework that executes compiler fixtures.

Currently, Sprout runs each fixture with a known set of inputs and annotations. Sprout compares execution outputs (i.e. return values and console logs) of original source code and the corresponding Forget-transformed version. We hope to add fuzzing capabilities to Sprout, synthesizing sets of program inputs based on type and/or effect annotations.

Sprout is now enabled for all fixtures! If Sprout cannot execute your fixture due to some technical limitations, add your fixture to SproutTodoFilter.ts with a comment explaining why.

Sprout CLI

Sprout can be run from packages/babel-plugin-react-forget. When adding new fixtures to Sprout, please check that fixture outputs look reasonable with yarn sprout --filter --verbose.

# rebuild when sprout or babel-plugin-react-forget changes
$ yarn sprout:build

# evaluate all test fixtures not listed in SproutTodoFilter
$ yarn sprout

# show all sprout options
$ yarn sprout --help
Options:
  --sync     Run compiler in main thread.
                          [boolean] [default: false]
  --filter   Evaluate fixtures in filter mode.
                          [boolean] [default: false]
  --verbose  Print all fixture outputs and logs.
                          [boolean] [default: false]

Sprout can be run in filter mode with yarn sprout --filter. Just like Snap, Sprout expects babel-plugin-react-forget/testfilter.txt be formatted as such.

  • first line: // @only or // @skip
  • all other lines: a test fixture name, i.e. the relative path from the compiler fixtures dir, without a .js or .expect.md extension.

Example:

// @only
console-readonly
constant-propagate-global-phis
dce-loop

Adding fixtures to Sprout

1. Annotate fixtures.

Each fixture test executed by Sprout needs to export const FIXTURE_ENTRYPOINT object with the following type signature.

type FixtureEntrypoint<T> = {
  // function to be invoked
  fn: ((...params: Array<T>) => any),
  // params to pass to fn
  // (if `fn` is a react component, this should be an array
  // with exactly one element -- props)
  params: Array<T>,
}

Example:

// test.js
function MyComponent(props) {
  return <div>{props.a + props.b}</div>;
}
export const FIXTURE_ENTRYPOINT = {
  fn: MyComponent,
  params: [{a: "hello ", b: "world"}],
};

2. Import / define helper functions.

  • Prefer importing helper functions for readability and simplicity.
  • Fixtures that require helper functions with specific types or mutability can define their own within the same fixture file.
// test.js
import { addOne } from 'shared-runtime';

function customHelper(val1, val2) {
  // This directive is important, as helper functions don't
  // always follow the rules of React.
  "use no forget";
  // ...
}

// ...

Notes

  • If your fixture needs to import from an external module, we currently only support importing from react (see Milestones todo list).

  • Any fixture can use React hooks, but they need to be first imported. We may later enforce that only isComponent: true fixtures can use React hooks.

    import {useState} from 'react';
    
  • If your fixture wants to export multiple functions to Sprout to run, please split up the fixture into multiple files (e.g. test-case-1, test-case-2, etc).

  • Sprout currently runs each fixture in an iife to prevent variable collisions, but it does not run fixtures in isolation. Please do not mutate any external state in fixtures.

  • Sprout does not run fixtures listed in SproutTodoFilter.ts, even in filter mode.

Milestones:

  • [] Render fixtures with React runtime / testing-library/react.
  • [] Make Sprout CLI -runnable and report results in process exit code.
  • [] Enable Sprout by default and run it in the Github Actions pipeline.
  • [🚧] Make all existing test fixtures Sprout compatible (see SproutTodoFilter.ts). This involves each fixture being annotated with FIXTURE_ENTRYPOINT and using shared functions and/or defining its own helpers.
    • 77 done, ~410 to go
  • (optional) Store Sprout output as snapshot files. i.e. each fixture could have a fixture.js, fixture.snap.md, and fixture.sprout.md.
  • Add support for fbt.