-
Notifications
You must be signed in to change notification settings - Fork 78
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
Test Renderer for TDD #515
Comments
I have looked at this a bit more and see two divergent ways of approaching this given the following use case:
Ideally, this utility would be hooked into the test runner so that it would work with the user's testing workflow. However this is difficult because it involves rendering in a browser and there are a variety of strategies to running tests, many of which (intern-node and jest in particular) don't involve a real browser. Thus this, The alternate approach is to hook into Example of rendering an assertion template in main.tsx// Can't have existing app render active
// const r = renderer(() => w(AppContainer, {}));
// r.mount({ registry });
const baseAssertion = assertionTemplate(() => (
<div {...{ '~key': 'root' }} classes={css.root}>
<h2 classes={css.title}>
Filter
<Button
key="onclose"
borderless
classes={{ 'demo/Button': { root: [css.closeLink] } }}
onClick={() => {
console.log('onClick called');
}}
>
<Icon icon="close" />
</Button>
</h2>
</div>
));
const t = renderer(baseAssertion.append('~root', ['test']) as () => WNode);
t.mount({ registry }); The problem is then, how do you fit into the user testing workflow. If you tried to import an assertion template or test harness from a unit test you again need to do something about the test runner. This would most likely be some form of mocking but it can get complicated pretty quickly. Example of test file that would need to be mocked out.import assertionTemplate from '@dojo/framework/testing/assertionTemplate';
import harness from '@dojo/framework/testing/harness';
import tddRenderUtil from '@dojo/framework/testing/tddRenderUtil`';
import { tsx } from '@dojo/framework/widget-core/tsx';
import Button from '../button/Button';
import Icon from '../icon/Icon';
import { RightMenu } from './RightMenu';
import * as css from './RightMenu.m.css';
import { myUtilThatGetsCalled } from './util';
import { mockFunction } from './testing-utils' // This could mean more mocking needed
// Would need to run these (test runner specific) describe/beforeEach/it blocks
describe('RightMenu', () => {
const baseAssertion = assertionTemplate(() => (
<div {...{ '~key': 'root' }} classes={css.root}>
<h2 classes={css.title}>
Filter
<Button
classes={{ 'demo/Button': { root: [css.closeLink] } }}
onClick={() => { console.log('onClick called'); }}
>
<Icon icon="close" />
</Button>
</h2>
</div>
));
let someSpy;
beforeEach(() => {
someSpy = spyOn(myUtilThatGetsCalled).andStub(() => {custom: 'return obj'});
});
it('default renders correctly', () => {
const h = harness(() => <RightMenu open={true} onClose={() => null} />);
tddRenderUtil(h.getRender()); // Does this block?
h.expect(baseAssertion);
});
it('alows changing the title', () => {
const h = harness(() => <RightMenu title="Custom Title" open={true} onClose={() => null} />);
tddRenderUtil( // Can you call this again?
baseAssertion.replace('h2', [
'Custom Title',
...baseAssertion.getChildren('h2').slice(1)
]) // Note: this is copying the existing code already
);
h.expect(
baseAssertion.replace('h2', [
'Custom Title',
...baseAssertion.getChildren('h2').slice(1)
])
);
});
it('calls the close callback', () => {
// We may not care about this test but it would need to be mocked correctly
const onClose = mockFunction();
const h = harness(() => <RightMenu open={true} onClose={onClose} />);
h.trigger('@onclose', 'onClick');
expect(onClose).toHaveBeenCalled();
});
}); To try to import test files gets back into the territory of dealing with different test runners, even if we entirely mock them out. It would be a lot of work put on the user and extra complexity. Considering that this is a tool for temporary test debugging, it might make more sense to have the user copy/paste the relevant code into a file specifically for the test render. Any test setup would need to be copied, but that would actually simplify the experience. Example of render file separate from tests// Could have own relevant helpers
export class SideBySide extends WidgetBase {
protected render() {
return (
<div style="display: flex; flex-direction: row">
<div style="width: 50%">{this.properties.expected()}</div>
<div style="width: 50%">{this.properties.harness.getRender()}</div>
</div>
);
}
}
const baseAssertion = assertionTemplate(() => (
<div {...{ "~key": "root" }} classes={css.root}>
<h2 classes={css.title}>
Filter
<Button
classes={{ "demo/Button": { root: [css.closeLink] } }}
onClick={() => {
console.log("onClick called");
}}
>
<Icon icon="close" />
</Button>
</h2>
</div>
));
// User can work here without messing up tests
const h = harness(() => <RightMenu open={true} onClose={() => null} />);
tddRenderUtil(() => <SideBySide expected={baseAssertion} harness={h} />); Technically, this is entirely available with Dojo, however it might be good to codify how this is done. There would need to be a simple way to toggle this render on/off without adding significant code to the final build. It could be as simple as having a file alongside SummaryGains
Drawbacks
|
Enhancement
I would like to have a way to render from tests as a way to aid with TDD. Ideally, you would be able to pass an assertion template or component instance to a helper function withing a test file and it would serve that component in a separate window. This would be helpful because you would be able to play with a component in isolation. You could adjust the css and dom structure of an assertion template before updating the component implementation.
Challenges
The text was updated successfully, but these errors were encountered: