import 'package:angel3_framework/angel3_framework.dart'; import 'package:angel3_seo/angel3_seo.dart'; import 'package:angel3_static/angel3_static.dart'; import 'package:angel3_test/angel3_test.dart'; import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:html/dom.dart' as html; import 'package:html/parser.dart' as html; import 'package:http_parser/http_parser.dart'; import 'package:logging/logging.dart'; import 'package:test/test.dart'; void main() { group('inlineAssets', () { group('buffer', inlineAssetsTests((app, dir) { app.get('/', (req, res) async { var indexHtml = dir.childFile('index.html'); var contents = await indexHtml.readAsBytes(); res ..useBuffer() ..contentType = MediaType.parse('text/html; charset=utf-8') ..buffer!.add(contents); }); app.responseFinalizers.add(inlineAssets(dir)); })); group('virtual_directory', inlineAssetsTests((app, dir) { var vDir = inlineAssetsFromVirtualDirectory( VirtualDirectory(app, dir.fileSystem, source: dir)); app.fallback(vDir.handleRequest); })); }); } /// Typedef for backwards-compatibility with Dart 1. typedef InlineAssetTest = void Function(Angel app, Directory dir); void Function() inlineAssetsTests(InlineAssetTest f) { return () { late TestClient client; setUp(() async { var app = Angel(); var fs = MemoryFileSystem(); var dir = fs.currentDirectory; f(app, dir); client = await connectTo(app); for (var path in contents.keys) { var file = fs.file(path); await file.writeAsString(contents[path]!.trim()); } app.logger = Logger('angel_seo') ..onRecord.listen((rec) { print(rec); if (rec.error != null) print(rec.error); if (rec.stackTrace != null) print(rec.stackTrace); }); }); tearDown(() => client.close()); group('sends html', () { late html.Document doc; setUp(() async { var res = await client.get(Uri.parse('/'), headers: {'accept': 'text/html'}); print(res.body); doc = html.parse(res.body); }); group('stylesheets', () { test('replaces <link> with <style>', () { expect(doc.querySelectorAll('link'), hasLength(1)); }); test('populates a <style>', () { var style = doc.querySelector('style'); expect(style?.innerHtml.trim(), contents['site.css']); }); test('heeds data-no-inline', () { var link = doc.querySelector('link')!; expect(link.attributes, containsPair('rel', 'stylesheet')); expect(link.attributes, containsPair('href', 'not-inlined.css')); expect(link.attributes.keys, isNot(contains('data-no-inline'))); }); test('preserves other attributes', () { var link = doc.querySelector('link')!; expect(link.attributes, containsPair('data-foo', 'bar')); }); }); group('scripts', () { test('does not replace <script> with anything', () { expect(doc.querySelectorAll('script'), hasLength(2)); }); test('populates innerHtml', () { var script0 = doc.querySelectorAll('script')[0]; expect(script0.innerHtml.trim(), contents['site.js']); }); test('heeds data-no-inline', () { var script1 = doc.querySelectorAll('script')[1]; expect(script1.attributes, containsPair('src', 'not-inlined.js')); expect(script1.attributes.keys, isNot(contains('data-no-inline'))); }); test('preserves other attributes', () { var script0 = doc.querySelectorAll('script')[0]; var script1 = doc.querySelectorAll('script')[1]; expect(script0.attributes, containsPair('data-foo', 'bar')); expect(script1.attributes, containsPair('type', 'text/javascript')); }); }); }); }; } var contents = <String, String>{ 'index.html': '''<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link rel="stylesheet" href="site.css"> <link data-foo="bar" rel="stylesheet" href="not-inlined.css" data-no-inline> <script data-foo="bar" src="site.js"></script> <script type="text/javascript" src="not-inlined.js" data-no-inline></script> <title>Angel SEO</title> </head> <body> <h1>Angel SEO</h1> <p>Embrace the power of inlined styles, etc.</p> </body> </html>''', 'not-inlined.css': '''p { font-style: italic; }''', 'not-inlined.js': '''window.addEventListener('load', function() { console.log('THIS message was not from an inlined file.'); });''', 'site.css': '''h1 { color: pink; }''', 'site.js': '''window.addEventListener('load', function() { console.log('Hello, inline world!'); });''' };