From 337880c0d430dfdb67e0d741befdd010fecdfd87 Mon Sep 17 00:00:00 2001 From: "jmesserly@google.com" Date: Thu, 5 Sep 2013 23:00:41 +0000 Subject: [PATCH] fixed TodoMVC tests to include deploying to JS R=kustermann@google.com, sigmund@google.com Review URL: https://codereview.chromium.org//23678009 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@27222 260f80e4-7a28-3924-810f-c04153c831b5 --- pkg/polymer/lib/deploy.dart | 95 +++++++++++++------ .../lib/src/transform/polyfill_injector.dart | 12 ++- .../test/transform/all_phases_test.dart | 6 +- pkg/polymer/test/transform/common.dart | 8 +- .../transform/polyfill_injector_test.dart | 9 +- tools/testing/dart/test_suite.dart | 76 +++++++++++---- 6 files changed, 150 insertions(+), 56 deletions(-) diff --git a/pkg/polymer/lib/deploy.dart b/pkg/polymer/lib/deploy.dart index 8d3c47b4e39..4c5b564d41e 100644 --- a/pkg/polymer/lib/deploy.dart +++ b/pkg/polymer/lib/deploy.dart @@ -33,12 +33,47 @@ import 'package:args/args.dart'; main() { var args = _parseArgs(new Options().arguments); if (args == null) return; + + var test = args['test']; + if (test != null) { + _initForTest(test); + } + print('polymer/deploy.dart: creating a deploy target for "$_currentPackage"'); var outDir = args['out']; - _run(args['webdir'], outDir).then( + _run(outDir, test != null).then( (_) => print('Done! All files written to "$outDir"')); } +// TODO(jmesserly): the current deploy/barback architecture is very unfriendly +// to deploying a single test. We need to fix it somehow but it isn't clear yet. +void _initForTest(String testFile) { + var testDir = path.normalize(path.dirname(testFile)); + + // A test must be allowed to import things in the package. + // So we must find its package root, given the entry point. We can do this + // by walking up to find pubspec.yaml. + var pubspecDir = _findDirWithFile(path.absolute(testDir), 'pubspec.yaml'); + if (pubspecDir == null) { + print('error: pubspec.yaml file not found, please run this script from ' + 'your package root directory or a subdirectory.'); + exit(1); + } + + _currentPackage = '_test'; + _packageDirs = {'_test' : pubspecDir}; +} + +String _findDirWithFile(String dir, String filename) { + while (!new File(path.join(dir, filename)).existsSync()) { + var parentDir = path.dirname(dir); + // If we reached root and failed to find it, bail. + if (parentDir == dir) return null; + dir = parentDir; + } + return dir; +} + /** * API exposed for testing purposes. Runs this deploy command but prentend that * the sources under [webDir] belong to package 'test'. @@ -48,46 +83,49 @@ Future runForTest(String webDir, String outDir) { // associate package dirs with their location in the repo: _packageDirs = {'test' : '.'}; - addPackages(String dir) { - for (var packageDir in new Directory(dir).listSync().map((d) => d.path)) { - _packageDirs[path.basename(packageDir)] = packageDir; - } - } - addPackages('..'); - addPackages('../third_party'); - addPackages('../../third_party/pkg'); + _addPackages('..'); + _addPackages('../third_party'); + _addPackages('../../third_party/pkg'); return _run(webDir, outDir); } -Future _run(String webDir, String outDir) { +_addPackages(String dir) { + for (var packageDir in new Directory(dir).listSync().map((d) => d.path)) { + _packageDirs[path.basename(packageDir)] = packageDir; + } +} + +Future _run(String outDir, bool includeTests) { var barback = new Barback(new _PolymerDeployProvider()); - _initializeBarback(barback, webDir); + _initializeBarback(barback, includeTests); _attachListeners(barback); - return _emitAllFiles(barback, webDir, outDir); + return _emitAllFiles(barback, 'web', outDir).then( + (_) => includeTests ? _emitAllFiles(barback, 'test', outDir) : null); } /** Tell barback which transformers to use and which assets to process. */ -void _initializeBarback(Barback barback, String webDir) { +void _initializeBarback(Barback barback, bool includeTests) { var assets = []; + void addAssets(String package, String subDir) { + for (var filepath in _listDir(package, subDir)) { + assets.add(new AssetId(package, filepath)); + } + } + for (var package in _packageDirs.keys) { // Do not process packages like 'polymer' where there is nothing to do. if (_ignoredPackages.contains(package)) continue; barback.updateTransformers(package, phases); // notify barback to process anything under 'lib' and 'asset' - for (var filepath in _listDir(package, 'lib')) { - assets.add(new AssetId(package, filepath)); - } - - for (var filepath in _listDir(package, 'asset')) { - assets.add(new AssetId(package, filepath)); - } + addAssets(package, 'lib'); + addAssets(package, 'asset'); } // In case of the current package, include also 'web'. - for (var filepath in _listDir(_currentPackage, webDir)) { - assets.add(new AssetId(_currentPackage, filepath)); - } + addAssets(_currentPackage, 'web'); + if (includeTests) addAssets(_currentPackage, 'test'); + barback.updateSources(assets); } @@ -235,12 +273,13 @@ final Set _ignoredPackages = ArgResults _parseArgs(arguments) { var parser = new ArgParser() - ..addFlag('help', abbr: 'h', help: 'Displays this help message', + ..addFlag('help', abbr: 'h', help: 'Displays this help message.', defaultsTo: false, negatable: false) - ..addOption('webdir', help: 'Directory containing the application', - defaultsTo: 'web') - ..addOption('out', abbr: 'o', help: 'Directory where to generated files', - defaultsTo: 'out'); + ..addOption('out', abbr: 'o', help: 'Directory where to generated files.', + defaultsTo: 'out') + ..addOption('test', help: 'Deploy the test at the given path.\n' + 'Note: currently this will deploy all tests in its directory,\n' + 'but it will eventually deploy only the specified test.'); try { var results = parser.parse(arguments); if (results['help']) { diff --git a/pkg/polymer/lib/src/transform/polyfill_injector.dart b/pkg/polymer/lib/src/transform/polyfill_injector.dart index d722d1be6ae..6b951139fb5 100644 --- a/pkg/polymer/lib/src/transform/polyfill_injector.dart +++ b/pkg/polymer/lib/src/transform/polyfill_injector.dart @@ -30,6 +30,7 @@ class PolyfillInjector extends Transformer { return readPrimaryAsHtml(transform).then((document) { bool shadowDomFound = false; bool jsInteropFound = false; + bool pkgJsInteropFound = false; bool dartScriptTags = false; for (var tag in document.queryAll('script')) { @@ -38,6 +39,8 @@ class PolyfillInjector extends Transformer { var last = src.split('/').last; if (last == 'interop.js') { jsInteropFound = true; + } else if (last == 'dart_interop.js') { + pkgJsInteropFound = true; } else if (_shadowDomJS.hasMatch(last)) { shadowDomFound = true; } @@ -54,6 +57,12 @@ class PolyfillInjector extends Transformer { return; } + if (!pkgJsInteropFound) { + // JS interop code is required for Polymer CSS shimming. + document.body.nodes.insert(0, parseFragment( + '\n')); + } + if (!jsInteropFound) { // JS interop code is required for Polymer CSS shimming. document.body.nodes.insert(0, parseFragment( @@ -63,8 +72,9 @@ class PolyfillInjector extends Transformer { if (!shadowDomFound) { // Insert at the beginning (this polyfill needs to run as early as // possible). + // TODO(jmesserly): this is .debug to workaround issue 13046. document.body.nodes.insert(0, parseFragment( - '\n')); + '\n')); } transform.addOutput( diff --git a/pkg/polymer/test/transform/all_phases_test.dart b/pkg/polymer/test/transform/all_phases_test.dart index a3826fad83f..743b199edc2 100644 --- a/pkg/polymer/test/transform/all_phases_test.dart +++ b/pkg/polymer/test/transform/all_phases_test.dart @@ -36,6 +36,7 @@ void main() { '' '$SHADOW_DOM_TAG' '$INTEROP_TAG' + '$PKG_JS_INTEROP_TAG' '' '' @@ -68,6 +69,7 @@ void main() { '' '$SHADOW_DOM_TAG' '$INTEROP_TAG' + '$PKG_JS_INTEROP_TAG' '' '' @@ -107,6 +109,7 @@ void main() { '' '$SHADOW_DOM_TAG' '$INTEROP_TAG' + '$PKG_JS_INTEROP_TAG' '
' '' @@ -158,6 +161,7 @@ void main() { '' '$SHADOW_DOM_TAG' '$INTEROP_TAG' + '$PKG_JS_INTEROP_TAG' '1' '' @@ -207,7 +211,7 @@ class $className extends ChangeNotifierBase { set $fieldName(int value) { __\$$fieldName = notifyPropertyChange(const Symbol('$fieldName'), __\$$fieldName, value); } - + $className($fieldName) : __\$$fieldName = $fieldName; } '''; diff --git a/pkg/polymer/test/transform/common.dart b/pkg/polymer/test/transform/common.dart index 8114feb61c3..f1d85000ab0 100644 --- a/pkg/polymer/test/transform/common.dart +++ b/pkg/polymer/test/transform/common.dart @@ -23,7 +23,7 @@ AssetId idFromString(String s) { class TestHelper implements PackageProvider { /** * Maps from an asset string identifier of the form 'package|path' to the - * file contents. + * file contents. */ final Map files; final Iterable packages; @@ -95,7 +95,11 @@ testPhases(String testName, List> phases, }); } +// TODO(jmesserly): this is .debug to workaround issue 13046. const SHADOW_DOM_TAG = - '\n'; + '\n'; const INTEROP_TAG = '\n'; + +const PKG_JS_INTEROP_TAG = + '\n'; diff --git a/pkg/polymer/test/transform/polyfill_injector_test.dart b/pkg/polymer/test/transform/polyfill_injector_test.dart index 4ccd148847f..e8bbb895494 100644 --- a/pkg/polymer/test/transform/polyfill_injector_test.dart +++ b/pkg/polymer/test/transform/polyfill_injector_test.dart @@ -35,7 +35,7 @@ void main() { }, { 'a|web/test.html': '' - '$SHADOW_DOM_TAG$INTEROP_TAG' + '$SHADOW_DOM_TAG$INTEROP_TAG$PKG_JS_INTEROP_TAG' '' '', }); @@ -45,12 +45,15 @@ void main() { '' '' '$SHADOW_DOM_TAG' - '$INTEROP_TAG', + '$INTEROP_TAG' + '$PKG_JS_INTEROP_TAG', }, { 'a|web/test.html': '' '' '$SHADOW_DOM_TAG' - '$INTEROP_TAG', + '$INTEROP_TAG' + '$PKG_JS_INTEROP_TAG' + '', }); } diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart index aeb782b9bd7..022574d63b3 100644 --- a/tools/testing/dart/test_suite.dart +++ b/tools/testing/dart/test_suite.dart @@ -969,33 +969,56 @@ class StandardTestSuite extends TestSuite { String dartWrapperFilename = '$tempDir/test.dart'; String compiledDartWrapperFilename = '$tempDir/test.js'; - String htmlPath = '$tempDir/test.html'; - if (isWrappingRequired && !isWebTest) { - // test.dart will import the dart test. - _createWrapperFile(dartWrapperFilename, filePath); - } else { - dartWrapperFilename = filename; - } - String scriptPath = (compiler == 'none') ? - dartWrapperFilename : compiledDartWrapperFilename; - scriptPath = _createUrlPathFromFile(new Path(scriptPath)); - - // Create the HTML file for the test. - RandomAccessFile htmlTest = - new File(htmlPath).openSync(mode: FileMode.WRITE); String content = null; Path dir = filePath.directoryPath; String nameNoExt = filePath.filenameWithoutExtension; Path pngPath = dir.append('$nameNoExt.png'); Path txtPath = dir.append('$nameNoExt.txt'); - Path customHtmlPath = dir.append('$nameNoExt.html'); + String customHtmlPath = dir.append('$nameNoExt.html').toNativePath(); + File customHtml = new File(customHtmlPath); Path expectedOutput = null; - if (new File(customHtmlPath.toNativePath()).existsSync()) { - // Use existing HTML document if available. - htmlPath = customHtmlPath.toNativePath(); + // Construct the command(s) that compile all the inputs needed by the + // browser test. For running Dart in DRT, this will be noop commands. + List commands = []; + + // Use existing HTML document if available. + String htmlPath; + if (customHtml.existsSync()) { + + // If necessary, run the Polymer deploy steps. + // TODO(jmesserly): this should be generalized for any tests that + // require Pub deploy, not just polymer. + if (compiler != 'none' && + customHtml.readAsStringSync().contains('polymer/boot.js')) { + + commands.add(_polymerDeployCommand( + customHtmlPath, tempDir, optionsFromFile)); + + htmlPath = '$tempDir/test/$nameNoExt.html'; + dartWrapperFilename = '${htmlPath}_bootstrap.dart'; + compiledDartWrapperFilename = '$dartWrapperFilename.js'; + } else { + htmlPath = customHtmlPath; + } } else { + htmlPath = '$tempDir/test.html'; + if (isWrappingRequired && !isWebTest) { + // test.dart will import the dart test. + _createWrapperFile(dartWrapperFilename, filePath); + } else { + dartWrapperFilename = filename; + } + + // Create the HTML file for the test. + RandomAccessFile htmlTest = + new File(htmlPath).openSync(mode: FileMode.WRITE); + + String scriptPath = (compiler == 'none') ? + dartWrapperFilename : compiledDartWrapperFilename; + scriptPath = _createUrlPathFromFile(new Path(scriptPath)); + if (new File(pngPath.toNativePath()).existsSync()) { expectedOutput = pngPath; content = getHtmlLayoutContents(scriptType, new Path("$scriptPath")); @@ -1010,9 +1033,6 @@ class StandardTestSuite extends TestSuite { htmlTest.closeSync(); } - // Construct the command(s) that compile all the inputs needed by the - // browser test. For running Dart in DRT, this will be noop commands. - List commands = []; if (compiler != 'none') { commands.add(_compileCommand( dartWrapperFilename, compiledDartWrapperFilename, @@ -1152,6 +1172,20 @@ class StandardTestSuite extends TestSuite { dart2JsBootstrapDependencies, compilerPath, args, configurationDir); } + /** Helper to create a Polymer deploy command for a single HTML file. */ + Command _polymerDeployCommand(String inputFile, String outputDir, + optionsFromFile) { + List args = []; + String packageRoot = packageRootArgument(optionsFromFile['packageRoot']); + if (packageRoot != null) args.add(packageRoot); + args..add('package:polymer/deploy.dart') + ..add('--test')..add(inputFile) + ..add('--out')..add(outputDir); + + return CommandBuilder.instance.getCommand( + 'polymer_deploy', vmFileName, args, configurationDir); + } + /** * Create a directory for the generated test. If a Dart language test * needs to be run in a browser, the Dart test needs to be embedded in