Skip to content

Commit

Permalink
Merge pull request #219 from Workiva/AF-2799_remove_mirrors_from_tests
Browse files Browse the repository at this point in the history
AF-2799: Remove mirrors from tests
  • Loading branch information
rmconsole5-wk authored Dec 28, 2018
2 parents 0617b4f + 4243465 commit 014965f
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 115 deletions.
105 changes: 52 additions & 53 deletions test/over_react/component/dom_components_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,63 +14,62 @@

library dom_components_test;

// Tell dart2js that this library only needs to reflect the specified types.
// This speeds up compilation and makes JS output much smaller.
@MirrorsUsed(targets: const [
'over_react.dom_components.Dom'
])
import 'dart:mirrors';

import 'package:over_react/over_react.dart';
import 'package:react/react_client.dart';
import 'package:test/test.dart';

main() {
group('Dom component:', () {
const expectedStaticMethods = const<Symbol>[
// DOM
#a, #abbr, #address, #area, #article, #aside, #audio, #b, #base, #bdi, #bdo, #big, #blockquote, #body, #br,
#button, #canvas, #caption, #cite, #code, #col, #colgroup, #data, #datalist, #dd, #del, #details, #dfn, #dialog,
#div, #dl, #dt, #em, #embed, #fieldset, #figcaption, #figure, #footer, #form, #h1, #h2, #h3, #h4, #h5, #h6,
#head, #header, #hr, #html, #i, #iframe, #img, #input, #ins, #kbd, #keygen, #label, #legend, #li, #link, #main,
#map, #mark, #menu, #menuitem, #meta, #meter, #nav, #noscript, #object, #ol, #optgroup, #option, #output, #p,
#param, #picture, #pre, #progress, #q, #rp, #rt, #ruby, #s, #samp, #script, #section, #select, #small, #source,
#span, #strong, #style, #sub, #summary, #sup, #table, #tbody, #td, #textarea, #tfoot, #th, #thead, #time,
#title, #tr, #track, #u, #ul, #variable, #video, #wbr,
// SVG
#svgA, #altGlyph, #altGlyphDef, #altGlyphItem, #animate, #animateColor, #animateMotion, #animateTransform,
#svgAudio, #svgCanvas, #circle, #clipPath, #colorProfile, #cursor, #defs, #desc, #discard, #ellipse, #feBlend,
#feColorMatrix, #feComponentTransfer, #feComposite, #feConvolveMatrix, #feDiffuseLighting, #feDisplacementMap,
#feDistantLight, #feDropShadow, #feFlood, #feFuncA, #feFuncB, #feFuncG, #feFuncR, #feGaussianBlur, #feImage,
#feMerge, #feMergeNode, #feMorphology, #feOffset, #fePointLight, #feSpecularLighting, #feSpotLight, #feTile,
#feTurbulence, #filter, #font, #fontFace, #fontFaceFormat, #fontFaceName, #fontFaceSrc, #fontFaceUri,
#foreignObject, #g, #glyph, #glyphRef, #hatch, #hatchpath, #hkern, #svgIframe, #image, #line, #linearGradient,
#marker, #mask, #mesh, #meshgradient, #meshpatch, #meshrow, #metadata, #missingGlyph, #mpath, #path, #pattern,
#polygon, #polyline, #radialGradient, #rect, #svgScript, #svgSet, #solidcolor, #stop, #svgStyle, #svg,
#svgSwitch, #symbol, #text, #textPath, #svgTitle, #tref, #tspan, #unknown, #use, #svgVideo, #view, #vkern,
];

List<Symbol> methods = [];
ClassMirror domClassMirror;

setUpAll(() {
domClassMirror = reflectClass(Dom);

// staticMembers is not implemented for the DDC and will throw is this test is loaded even if it's not run.
try {
methods = domClassMirror.staticMembers.values.map((m) => m.simpleName).toList();
var expectedMethodsOnDom = <Function /* dom method */, String /* method name */>{
Dom.a: 'a', Dom.abbr: 'abbr', Dom.address: 'address', Dom.area: 'area', Dom.article: 'article',
Dom.aside: 'aside', Dom.audio: 'audio', Dom.b: 'b', Dom.base: 'base', Dom.bdi: 'bdi', Dom.bdo: 'bdo',
Dom.big: 'big', Dom.blockquote: 'blockquote', Dom.body: 'body', Dom.br: 'br', Dom.button: 'button',
Dom.canvas: 'canvas', Dom.caption: 'caption', Dom.cite: 'cite', Dom.code: 'code', Dom.col: 'col',
Dom.colgroup: 'colgroup', Dom.data: 'data', Dom.datalist: 'datalist', Dom.dd: 'dd', Dom.del: 'del',
Dom.details: 'details', Dom.dfn: 'dfn', Dom.dialog: 'dialog', Dom.div: 'div', Dom.dl: 'dl', Dom.dt: 'dt',
Dom.em: 'em', Dom.embed: 'embed', Dom.fieldset: 'fieldset', Dom.figcaption: 'figcaption', Dom.figure: 'figure',
Dom.footer: 'footer', Dom.form: 'form', Dom.h1: 'h1', Dom.h2: 'h2', Dom.h3: 'h3', Dom.h4: 'h4', Dom.h5: 'h5',
Dom.h6: 'h6', Dom.head: 'head', Dom.header: 'header', Dom.hr: 'hr', Dom.html: 'html', Dom.i: 'i',
Dom.iframe: 'iframe', Dom.img: 'img', Dom.input: 'input', Dom.ins: 'ins', Dom.kbd: 'kbd', Dom.keygen: 'keygen',
Dom.label: 'label', Dom.legend: 'legend', Dom.li: 'li', Dom.link: 'link', Dom.main: 'main', Dom.map: 'map',
Dom.mark: 'mark', Dom.menu: 'menu', Dom.menuitem: 'menuitem', Dom.meta: 'meta', Dom.meter: 'meter',
Dom.nav: 'nav', Dom.noscript: 'noscript', Dom.object: 'object', Dom.ol: 'ol', Dom.optgroup: 'optgroup',
Dom.option: 'option', Dom.output: 'output', Dom.p: 'p', Dom.param: 'param', Dom.picture: 'picture',
Dom.pre: 'pre', Dom.progress: 'progress', Dom.q: 'q', Dom.rp: 'rp', Dom.rt: 'rt', Dom.ruby: 'ruby', Dom.s: 's',
Dom.samp: 'samp', Dom.script: 'script', Dom.section: 'section', Dom.select: 'select', Dom.small: 'small',
Dom.source: 'source', Dom.span: 'span', Dom.strong: 'strong', Dom.style: 'style', Dom.sub: 'sub',
Dom.summary: 'summary', Dom.sup: 'sup', Dom.table: 'table', Dom.tbody: 'tbody', Dom.td: 'td',
Dom.textarea: 'textarea', Dom.tfoot: 'tfoot', Dom.th: 'th', Dom.thead: 'thead', Dom.time: 'time',
Dom.title: 'title', Dom.tr: 'tr', Dom.track: 'track', Dom.u: 'u', Dom.ul: 'ul', Dom.variable: 'variable',
Dom.video: 'video', Dom.wbr: 'wbr',
// SVG
Dom.svgA: 'svgA', Dom.altGlyph: 'altGlyph', Dom.altGlyphDef: 'altGlyphDef', Dom.altGlyphItem: 'altGlyphItem',
Dom.animate: 'animate', Dom.animateColor: 'animateColor', Dom.animateMotion: 'animateMotion',
Dom.animateTransform: 'animateTransform', Dom.svgAudio: 'svgAudio', Dom.svgCanvas: 'svgCanvas', Dom.circle: 'circle',
Dom.clipPath: 'clipPath', Dom.colorProfile: 'colorProfile', Dom.cursor: 'cursor', Dom.defs: 'defs', Dom.desc: 'desc',
Dom.discard: 'discard', Dom.ellipse: 'ellipse', Dom.feBlend: 'feBlend', Dom.feColorMatrix: 'feColorMatrix',
Dom.feComponentTransfer: 'feComponentTransfer', Dom.feComposite: 'feComposite', Dom.feConvolveMatrix: 'feConvolveMatrix',
Dom.feDiffuseLighting: 'feDiffuseLighting', Dom.feDisplacementMap: 'feDisplacementMap',
Dom.feDistantLight: 'feDistantLight', Dom.feDropShadow: 'feDropShadow', Dom.feFlood: 'feFlood', Dom.feFuncA: 'feFuncA',
Dom.feFuncB: 'feFuncB', Dom.feFuncG: 'feFuncG', Dom.feFuncR: 'feFuncR', Dom.feGaussianBlur: 'feGaussianBlur',
Dom.feImage: 'feImage', Dom.feMerge: 'feMerge', Dom.feMergeNode: 'feMergeNode', Dom.feMorphology: 'feMorphology',
Dom.feOffset: 'feOffset', Dom.fePointLight: 'fePointLight', Dom.feSpecularLighting: 'feSpecularLighting',
Dom.feSpotLight: 'feSpotLight', Dom.feTile: 'feTile', Dom.feTurbulence: 'feTurbulence', Dom.filter: 'filter',
Dom.font: 'font', Dom.fontFace: 'fontFace', Dom.fontFaceFormat: 'fontFaceFormat', Dom.fontFaceName: 'fontFaceName',
Dom.fontFaceSrc: 'fontFaceSrc', Dom.fontFaceUri: 'fontFaceUri', Dom.foreignObject: 'foreignObject', Dom.g: 'g',
Dom.glyph: 'glyph', Dom.glyphRef: 'glyphRef', Dom.hatch: 'hatch', Dom.hatchpath: 'hatchpath', Dom.hkern: 'hkern',
Dom.svgIframe: 'svgIframe', Dom.image: 'image', Dom.line: 'line', Dom.linearGradient: 'linearGradient',
Dom.marker: 'marker', Dom.mask: 'mask', Dom.mesh: 'mesh', Dom.meshgradient: 'meshgradient', Dom.meshpatch: 'meshpatch',
Dom.meshrow: 'meshrow', Dom.metadata: 'metadata', Dom.missingGlyph: 'missingGlyph', Dom.mpath: 'mpath', Dom.path: 'path',
Dom.pattern: 'pattern', Dom.polygon: 'polygon', Dom.polyline: 'polyline', Dom.radialGradient: 'radialGradient',
Dom.rect: 'rect', Dom.svgScript: 'svgScript', Dom.svgSet: 'svgSet', Dom.solidcolor: 'solidcolor', Dom.stop: 'stop',
Dom.svgStyle: 'svgStyle', Dom.svg: 'svg', Dom.svgSwitch: 'svgSwitch', Dom.symbol: 'symbol', Dom.text: 'text',
Dom.textPath: 'textPath', Dom.svgTitle: 'svgTitle', Dom.tref: 'tref', Dom.tspan: 'tspan', Dom.unknown: 'unknown',
Dom.use: 'use', Dom.svgVideo: 'svgVideo', Dom.view: 'view', Dom.vkern: 'vkern',
};

expect(methods, isNotEmpty, reason: 'should have properly reflected the static members.');
} catch(e) {}

if (methods.isNotEmpty) {
expect(methods, unorderedEquals(expectedStaticMethods), reason: '`expectedStaticMethods` needs to be updated');
}
});

for (var element in expectedStaticMethods) {
String name = MirrorSystem.getName(element);
String expectedTagName = name;
expectedMethodsOnDom.forEach((method, methodName) {
String expectedTagName = methodName;
if (expectedTagName == 'variable') expectedTagName = 'var';
if (expectedTagName == 'svgSet') expectedTagName = 'set';
if (expectedTagName == 'svgSwitch') expectedTagName = 'switch';
Expand All @@ -83,12 +82,12 @@ main() {
if (expectedTagName == 'missingGlyph') expectedTagName = 'missing-glyph';
if (expectedTagName.startsWith(new RegExp('svg.'))) expectedTagName = expectedTagName.substring(3);

test('Dom.$name generates the correct type', () {
DomProps builder = domClassMirror.invoke(element, []).reflectee;
test('${method.toString()} generates the correct type', () {
DomProps builder = method();
ReactElement component = builder();
expect(component.type, equalsIgnoringCase(expectedTagName));
});
}
});

group('typing:', () {
final DomProps dom = Dom.div();
Expand Down
67 changes: 51 additions & 16 deletions test/over_react/component/prop_mixins_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,15 @@ import '../../test_util/prop_utils.dart';

main() {
group('ReactProps', () {
testKeys(ReactPropsMixin.meta.keys, (() => new ReactPropMixinsTest({})));
testInvalidKey((() => new ReactPropMixinsTest({})));
test('uses unnamespaced keys', () {
// Test two keys to reduce the possibility that the key we picked might have a custom @Accessor annotation on it
expect(
new ReactPropMixinsTest({})
..ref = null
..key = null,
{'ref': null, 'key': null});
});

group('prop: key can have its value set to', () {
test('an int and be read as a String', () {
Expand All @@ -50,19 +58,47 @@ main() {
});

group('CssClassProps', () {
testKeys(CssClassPropsMixin.meta.keys, (() => new CssClassPropMixinsTest({})));
testInvalidKey((() => new CssClassPropMixinsTest({})));
test('uses unnamespaced keys', () {
// Test two keys to reduce the possibility that the key we picked might have a custom @Accessor annotation on it
expect(new CssClassPropMixinsTest({})..className = null..classNameBlacklist = null, {'className': null, 'classNameBlacklist': null});
});
});

group('DomPropsMixin', () {
testKeys(DomPropsMixin.meta.keys, (() => new DomPropMixinsTest({})));
testInvalidKey((() => new DomPropMixinsTest({})));
test('uses unnamespaced keys', () {
// Test two keys to reduce the possibility that the key we picked might have a custom @Accessor annotation on it
expect(
new DomPropMixinsTest({})
..style = null
..id = null,
{'style': null, 'id': null});
});
});

group('SvgPropsMixin', () {
testKeys(SvgPropsMixin.meta.keys, (() => new SvgPropMixinsTest({})));
testInvalidKey((() => new SvgPropMixinsTest({})));
test('uses unnamespaced keys', () {
// Test two keys to reduce the possibility that the key we picked might have a custom @Accessor annotation on it
expect(
new SvgPropMixinsTest({})
..clipPath = null
..cx= null,
{'clipPath': null, 'cx': null});
});
});

group('UbiquitousProps', () {
testKeys(UbiquitousDomPropsMixin.meta.keys, (() => new UbiquitousPropMixinsTest({})));
testInvalidKey((() => new UbiquitousPropMixinsTest({})));
test('uses unnamespaced keys', () {
// Test two keys to reduce the possibility that the key we picked might have a custom @Accessor annotation on it
expect(
new UbiquitousPropMixinsTest({})
..tabIndex = null
..id = null,
{'tabIndex': null, 'id': null});
});

group('has a getter that provides a typed view of', () {
test('aria props', () {
Expand All @@ -86,17 +122,16 @@ main() {
});

group('AriaProps', () {
test('cannot set / read values that are not its prop map', () {
var instance = new AriaPropMixinsTest({});
expect(() {instance['notThere'];}, throwsArgumentError);
});

for (var propKey in AriaPropsMixin.meta.keys) {
test('prop: $propKey can have its value set / read', () {
var instance = new AriaPropMixinsTest({});
testProp(new Symbol(propKey.replaceFirst('aria-', '')), propKey, instance, null);
});
}
testInvalidKey(() => new AriaPropMixinsTest({}));

test('uses unnamespaced keys with \'aria-\' prefix', () {
// Test two keys to reduce the possibility that the key we picked might have a custom @Accessor annotation on it
expect(
new AriaPropMixinsTest({})
..activedescendant = null
..atomic = null,
{'aria-activedescendant': null, 'aria-atomic': null});
});
});
}

Expand Down
23 changes: 0 additions & 23 deletions test/test_util/mock_classes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,6 @@ library mock_classes;
import 'dart:async';
import 'dart:html';

// Tell dart2js that the `mockito` package only needs to reflect the specified mock/spied types.
// This speeds up compilation and makes JS output much smaller.
@MirrorsUsed(targets: const [
'dart.async.Timer',
'MockTimer',
// Also include Mock classes we use from w_test_tools.
'dart.dom.html.KeyEvent',
'dart.dom.html.HtmlDocument',
'w_test_tools.src.mock_classes.MockKeyEvent',
'w_test_tools.src.mock_classes.MockDocument',
'MockFileList',
'MockFile',
'MockFileUploadInputElement',
'dart.dom.html.FileList',
'dart.dom.html.File',
'dart.dom.html.FileUploadInputElement',
'MockSyntheticEvent',
'MockSyntheticMouseEvent',
'react.SyntheticEvent',
'react.SyntheticMouseEvent',
], override: 'mockito')
import 'dart:mirrors';

import 'package:mockito/mockito.dart';
import 'package:react/react.dart' as react;

Expand Down
24 changes: 1 addition & 23 deletions test/test_util/prop_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,13 @@

library test_util.prop_utils;

// Tell dart2js that this library only needs to reflect types annotated with `Props`/`PropsMixin`.
// This speeds up compilation and makes JS output much smaller.
@MirrorsUsed(metaTargets: const [
'over_react.component_declaration.annotations.Props',
'over_react.component_declaration.annotations.PropsMixin',
])
import 'dart:mirrors';

import 'package:over_react_test/over_react_test.dart';
import 'package:test/test.dart';

void testProp(Symbol name, dynamic expectedKey, instance, testValue) {
InstanceMirror mirror = reflect(instance);

mirror.setField(name, testValue);
expect(instance[expectedKey], equals(testValue));
expect(mirror.getField(name).reflectee, equals(testValue));
}

void testKeys(List<String> keys, dynamic instanceBuilder()) {
void testInvalidKey(dynamic instanceBuilder()) {
test('cannot set / read values that are not its prop map', () {
var instance = instanceBuilder();
expect(() {instance['notThere'];},
throwsA(hasToStringValue(contains('Map does not contain this key'))));
});
for (var propKey in keys) {
test('prop: $propKey can have its value set / read', () {
var instance = instanceBuilder();
testProp(new Symbol(propKey), propKey, instance, null);
});
}
}

0 comments on commit 014965f

Please sign in to comment.