testRequiredProps function
- @isTestGroup
- BuilderOnlyUiFactory<
UiProps> factory, - dynamic childrenFactory()
Common test for verifying that props annotated as a requiredProp
are validated correctly.
Typically not consumed standalone. Use commonComponentTests instead.
Note: All required props must be provided by factory
.
Implementation
@isTestGroup
void testRequiredProps(BuilderOnlyUiFactory factory, dynamic childrenFactory()) {
late bool isComponent2;
var keyToErrorMessage = {};
var nullableProps = <String>[];
var requiredProps = <String>[];
setUp(() {
// This can't go in a setUpAll since it would be called before consumer setUps.
//
// ignore: invalid_use_of_protected_member
final version = ReactDartComponentVersion.fromType(
(factory()(childrenFactory())).type,
);
// ignore: invalid_use_of_protected_member
isComponent2 = version == ReactDartComponentVersion.component2;
var jacket = mount(factory()(childrenFactory()), autoTearDown: false);
var consumedProps = (jacket.getDartInstance() as component_base.UiComponent).consumedProps!;
jacket.unmount();
for (var consumedProp in consumedProps) {
for (var prop in consumedProp.props) {
if (!prop.isLate) {
if (prop.isNullable) {
nullableProps.add(prop.key);
} else if (prop.isRequired) {
requiredProps.add(prop.key);
}
}
keyToErrorMessage[prop.key] = prop.errorMessage;
}
}
});
testFunction('throws (component1) or logs the correct errors (component2) when the required prop is not set or is null', () {
void component1RequiredPropsTest(){
for (var propKey in requiredProps) {
final reactComponentFactory = factory()
.componentFactory as ReactDartComponentFactoryProxy; // ignore: avoid_as
// Props that are defined in the default props map will never not be set.
if (!reactComponentFactory.defaultProps.containsKey(propKey)) {
var badRenderer = () =>
render((factory()
..remove(propKey)
)(childrenFactory()));
expect(badRenderer,
throwsPropError_Required(propKey, keyToErrorMessage[propKey]),
reason: '$propKey is not set');
}
var propsToAdd = {propKey: null};
var badRenderer = () =>
render((factory()
..addAll(propsToAdd)
)(childrenFactory()));
expect(badRenderer,
throwsPropError_Required(propKey, keyToErrorMessage[propKey]),
reason: '$propKey is set to null');
}
}
void component2RequiredPropsTest() {
PropTypes.resetWarningCache();
var consoleErrors = <String?>[];
final originalConsoleError = context['console']['error'] as JsFunction;
addTearDown(() => context['console']['error'] = originalConsoleError);
context['console']['error'] = JsFunction.withThis((self, [message, arg1, arg2, arg3, arg4, arg5]) {
consoleErrors.add(message);
originalConsoleError.apply([message, arg1, arg2, arg3, arg4, arg5],
thisArg: self);
});
final reactComponentFactory = factory().componentFactory as
ReactDartComponentFactoryProxy2; // ignore: avoid_as
for (var propKey in requiredProps) {
if (!reactComponentFactory.defaultProps.containsKey(propKey)) {
try {
mount((factory()
..remove(propKey)
)(childrenFactory()));
} catch (_){}
expect(consoleErrors, isNotEmpty, reason: 'should have outputted a warning');
if (keyToErrorMessage[propKey] != '') {
expect(consoleErrors, [contains(keyToErrorMessage[propKey])],
reason: '$propKey is not set');
}
consoleErrors = [];
PropTypes.resetWarningCache();
}
var propsToAdd = {propKey: null};
try {
mount((factory()
..addAll(propsToAdd)
)(childrenFactory()));
} catch (_) {}
expect(consoleErrors, isNotEmpty, reason: 'should have outputted a warning');
if (keyToErrorMessage[propKey] != '') {
expect(consoleErrors, [contains(keyToErrorMessage[propKey])],
reason: '$propKey is not set');
}
consoleErrors = [];
PropTypes.resetWarningCache();
}
}
isComponent2 ? component2RequiredPropsTest() : component1RequiredPropsTest();
});
testFunction('nullable props', () {
if (!isComponent2) {
for (var propKey in nullableProps) {
final reactComponentFactory = factory().componentFactory as
ReactDartComponentFactoryProxy; // ignore: avoid_as
// Props that are defined in the default props map will never not be set.
if (!reactComponentFactory.defaultProps.containsKey(propKey)) {
var badRenderer = () => render((factory()..remove(propKey))(childrenFactory()));
expect(badRenderer, throwsPropError_Required(propKey, keyToErrorMessage[propKey]), reason: 'should throw when the required, nullable prop $propKey is not set');
var propsToAdd = {propKey: null};
badRenderer = () => render((factory()
..addAll(propsToAdd)
)(childrenFactory()));
expect(badRenderer, returnsNormally, reason: 'does not throw when the required, nullable prop $propKey is set to null');
}
}
} else {
PropTypes.resetWarningCache();
var consoleErrors = <String?>[];
final originalConsoleError = context['console']['error'] as JsFunction;
addTearDown(() => context['console']['error'] = originalConsoleError);
context['console']['error'] = JsFunction.withThis((self, [message, arg1, arg2, arg3, arg4, arg5]) {
consoleErrors.add(message);
originalConsoleError.apply([message, arg1, arg2, arg3, arg4, arg5],
thisArg: self);
});
final reactComponentFactory = factory().componentFactory as
ReactDartComponentFactoryProxy2; // ignore: avoid_as
for (var propKey in nullableProps) {
// Props that are defined in the default props map will never not be set.
if (!reactComponentFactory.defaultProps.containsKey(propKey)) {
try {
mount((factory()
..remove(propKey)
)(childrenFactory()));
} catch(_) {}
expect(consoleErrors, isNotEmpty, reason: 'should have outputted a warning');
if (keyToErrorMessage[propKey] != '') {
expect(consoleErrors, [contains(keyToErrorMessage[propKey])], reason: '$propKey is not set');
}
consoleErrors = [];
PropTypes.resetWarningCache();
}
var propsToAdd = {propKey: null};
try {
mount((factory()
..addAll(propsToAdd)
)(childrenFactory()));
} catch (_) {}
expect(consoleErrors, isEmpty, reason: 'should not have output a warning');
consoleErrors = [];
PropTypes.resetWarningCache();
}
}
});
}