Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better Harness and Assertion Template support for render props #529

Closed
matt-gadd opened this issue Sep 10, 2019 · 1 comment · Fixed by #710
Closed

Better Harness and Assertion Template support for render props #529

matt-gadd opened this issue Sep 10, 2019 · 1 comment · Fixed by #710
Labels
area: testing Testing enhancement New feature or request next Issue/Pull Request for the next major version

Comments

@matt-gadd
Copy link
Contributor

matt-gadd commented Sep 10, 2019

Enhancement
Assertion Templates have made creating/modifying assertions a lot easier for testing, but it's still really difficult to call and assert against render props, which mostly involves abusing the trigger func and asserting raw DNodes rather than using an Assertion Template. It would be nice to improve the ergonomics of this so a user can write these the same as any other Assertion Template.

This might be more achievable with: #528

@matt-gadd matt-gadd added enhancement New feature or request next Issue/Pull Request for the next major version area: testing Testing labels Sep 10, 2019
@agubler agubler mentioned this issue Sep 10, 2019
@agubler
Copy link
Member

agubler commented Mar 25, 2020

Problem

When working with the testing harness there is no built in support for working with render properties and as a result requires workarounds using the trigger. In addition to that there is no ergonomic way to:

  1. Target a known node in the rendered output tree
  2. Have typings for what properties are available and their expected params using trigger

This is due to trigger using an opaque selector to find a node in the tree and call a property.

import { create, tsx } from "@dojo/framework/core/vdom";
import assertionTemplate from "@dojo/framework/testing/assertionTemplate";
import harness from "@dojo/framework/testing/harness";
import { RenderResult } from "@dojo/framework/core/interfaces";

const rendererFactory = create().properties<{
  renderer: (text: string) => RenderResult;
}>();

const MyRenderingWidget = rendererFactory(function MyRenderingWidget({
  properties
}) {
  const { renderer } = properties();
  return <div>{renderer("hello")}</div>;
});

const factory = create();

const MyWidget = factory(function MyWidget() {
  return (
    <div>
      <span>content</span>
      <MyRenderingWidget
        key="renderer"
        renderer={value => {
          return <div>{`${value}, renderer`}</div>;
        }}
      />
    </div>
  );
});

const baseAssertion = assertionTemplate(() => {
  return (
    <div>
      <span>content</span>
      <MyRenderingWidget key="renderer" renderer={() => undefined} />
    </div>
  );
});

const h = harness(() => <MyWidget />);

// base assertion does not include the renderer content
h.expect(baseAssertion);

// opaque selector for calling the renderer function, no typings for the
// functions arguments
const result = h.trigger("@renderer", "renderer", "hello");

// a second template is required to assert the renderers output
const rendererAssertion = assertionTemplate(() => <div>hello, renderer</div>);

// using expect with both an expected and actual result
// that is returned from the trigger
h.expect(rendererAssertion, () => result);

Proposal

Dojo 7 introduces support for typed children when using function-based components, this is the recommended way to implement functionality that could previously only be done using render props. With this core support the harness should be enhanced to be able to test the expected output from the functional children in an ergonomic and typed way.

To do this the harness requires a way to identify nodes in the widgets output and render resolve the functional children inline. A way to support this is to provide a wrapping function for when they want to assert the return of functional children. This wrapped value would be used in the expected tree in place of the actual expected widget. This will enable the harness to be able to take instructions for the wrapped nodes and resolve them at assertion time. It also means that the harness can provide typings for the functional children and parameters.

import { create, tsx } from "@dojo/framework/core/vdom";
import assertionTemplate from "@dojo/framework/testing/assertionTemplate";
import harness, { wrap } from "@dojo/framework/testing/harness";
import { RenderResult } from "@dojo/framework/core/interfaces";

const rendererFactory = create().children<(text: string) => RenderResult>();

const MyRenderingWidget = rendererFactory(function MyRenderingWidget({ children }) {
  const [renderer] = children();
  return <div>{renderer("hello")}</div>;
});

const factory = create();

const MyWidget = factory(function MyWidget() {
  return (
    <div>
      <span>content</span>
      <MyRenderingWidget>{(value) => <div>{`${value}, renderer`}</div>}</MyRenderingWidget>
    </div>
  );
});

const WrappedMyRenderingWidget = wrap(MyRenderingWidget);

const baseAssertion = assertionTemplate(() => {
  return (
    <div>
      <span>content</span>
      <WrappedMyRenderingWidget>{() => <div>hello, renderer</div>}</WrappedMyRenderingWidget>
    </div>
  );
});

const h = harness(() => <MyWidget />);

// child API that instructs the harness to resolve the expected and actual child
// during the assertion. The children function parameters are typed appropriately
h.child(WrappedMyRenderingWidget, ['hello']);

// single assertion against the assertion template
h.expect(baseAssertion);

Creating "wrapped" widgets enables the harness to track the required instructions and resolve them automatically during the assertion.

As well as children, the wrapped widgets can be used to call node properties during the expectation providing the same type safety as provided by the harness.child API.

@agubler agubler mentioned this issue Mar 31, 2020
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: testing Testing enhancement New feature or request next Issue/Pull Request for the next major version
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants