* chore: update Flutter SDK to version 3.38.5 Upgrade Flutter from 3.32.4 to 3.38.5 to meet awesome_lints requirement for Dart SDK 3.10.0+. Update CI workflow to use the new Flutter version and add custom_lint verification step. * chore: integrate awesome_lints with custom lint rules Add awesome_lints and custom_lint dependencies, configure analysis_options.yaml to enable newline lint rules: newline_before_case, newline_before_constructor, newline_before_method, and newline_before_return. * style: apply newline formatting per awesome_lints rules Add blank lines before case clauses, return statements, method declarations, and constructors throughout the codebase to comply with awesome_lints newline rules. * fix: replace deprecated translate with leftTranslateByDouble Update Matrix4.translate() calls to use the new leftTranslateByDouble() API to resolve deprecation warnings in Flutter SDK 3.38.5. * chore: improve code readability with blank line formatting
372 lines
22 KiB
Dart
372 lines
22 KiB
Dart
import 'package:appflowy_editor/appflowy_editor.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
group('html_document_test.dart', () {
|
|
// Foo Bar
|
|
test('sample 1', () {
|
|
const html = '<p>Foo Bar</p>';
|
|
final document = htmlToDocument(html);
|
|
expect(document.root.children.length, 1);
|
|
expect(document.nodeAtPath([0])!.type, ParagraphBlockKeys.type);
|
|
expect(document.nodeAtPath([0])!.delta!.toPlainText(), 'Foo Bar');
|
|
});
|
|
|
|
// * Foo
|
|
// * Bar
|
|
// * Baz
|
|
test('sample 2', () {
|
|
const html = '''<ul>
|
|
<li>Foo</li>
|
|
<li>Bar</li>
|
|
<li>Baz</li>
|
|
</ul>''';
|
|
final document = htmlToDocument(html);
|
|
expect(document.root.children.length, 3);
|
|
expect(document.nodeAtPath([0])!.type, BulletedListBlockKeys.type);
|
|
expect(document.nodeAtPath([0])!.delta!.toPlainText(), 'Foo');
|
|
expect(document.nodeAtPath([1])!.type, BulletedListBlockKeys.type);
|
|
expect(document.nodeAtPath([1])!.delta!.toPlainText(), 'Bar');
|
|
expect(document.nodeAtPath([2])!.type, BulletedListBlockKeys.type);
|
|
expect(document.nodeAtPath([2])!.delta!.toPlainText(), 'Baz');
|
|
});
|
|
|
|
// Hello
|
|
// * Foo
|
|
// * Bar
|
|
// * Baz
|
|
test('sample 3', () {
|
|
const html = '''<p>Hello</p>
|
|
<ul>
|
|
<li>Foo</li>
|
|
<li>Bar</li>
|
|
<li>Baz</li>
|
|
</ul>''';
|
|
final document = htmlToDocument(html);
|
|
expect(document.root.children.length, 4);
|
|
expect(document.nodeAtPath([0])!.type, ParagraphBlockKeys.type);
|
|
expect(document.nodeAtPath([0])!.delta!.toPlainText(), 'Hello');
|
|
expect(document.nodeAtPath([1])!.type, BulletedListBlockKeys.type);
|
|
expect(document.nodeAtPath([1])!.delta!.toPlainText(), 'Foo');
|
|
expect(document.nodeAtPath([2])!.type, BulletedListBlockKeys.type);
|
|
expect(document.nodeAtPath([2])!.delta!.toPlainText(), 'Bar');
|
|
expect(document.nodeAtPath([3])!.type, BulletedListBlockKeys.type);
|
|
expect(document.nodeAtPath([3])!.delta!.toPlainText(), 'Baz');
|
|
});
|
|
|
|
// * Foo
|
|
// * Bar
|
|
// * Baz
|
|
test('sample 4', () {
|
|
const html = '''<ul>
|
|
<li>Foo
|
|
<ul>
|
|
<li>Bar
|
|
<ul>
|
|
<li>Baz</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>''';
|
|
final document = htmlToDocument(html);
|
|
expect(document.root.children.length, 1);
|
|
final foo = document.nodeAtPath([0])!;
|
|
final bar = document.nodeAtPath([0, 0])!;
|
|
final baz = document.nodeAtPath([0, 0, 0])!;
|
|
expect(foo.type, BulletedListBlockKeys.type);
|
|
expect(foo.delta!.toPlainText(), 'Foo');
|
|
expect(bar.parent, foo);
|
|
expect(bar.type, BulletedListBlockKeys.type);
|
|
expect(bar.delta!.toPlainText(), 'Bar');
|
|
expect(baz.parent, bar);
|
|
expect(baz.type, BulletedListBlockKeys.type);
|
|
expect(baz.delta!.toPlainText(), 'Baz');
|
|
});
|
|
|
|
// copy from Notion
|
|
// There's a line with different formats, such as **bold**, __italic__, underline, ~~strikethrough~~, and `inline code`.
|
|
test('sample 5', () {
|
|
const html =
|
|
'''<meta charset='utf-8'>There's a line with different formats, such as <span style="font-weight:600" data-token-index="1" class="notion-enable-hover">bold</span>, <span style="font-style:italic" data-token-index="3" class="notion-enable-hover">italic</span>, <span style="color:inherit;border-bottom:0.05em solid;word-wrap:break-word" data-token-index="5" class="notion-enable-hover">underline</span>, <span style="text-decoration:line-through" data-token-index="7" class="notion-enable-hover">strikethrough</span>, and <span style="font-family:"SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace;line-height:normal;background:rgba(135,131,120,0.15);color:#EB5757;border-radius:3px;font-size:85%;padding:0.2em 0.4em" data-token-index="9" spellcheck="false" class="notion-enable-hover">inline code</span>.''';
|
|
final document = htmlToDocument(html);
|
|
final delta = document.nodeAtPath([0])!.delta!;
|
|
expect(
|
|
delta.toJson(),
|
|
[
|
|
{"insert": "There's a line with different formats, such as "},
|
|
{
|
|
"insert": "bold",
|
|
"attributes": {"bold": true},
|
|
},
|
|
{"insert": ", "},
|
|
{
|
|
"insert": "italic",
|
|
"attributes": {"italic": true},
|
|
},
|
|
{"insert": ", underline, "},
|
|
{
|
|
"insert": "strikethrough",
|
|
"attributes": {"strikethrough": true},
|
|
},
|
|
{"insert": ", and "},
|
|
{
|
|
"insert": "inline code",
|
|
"attributes": {
|
|
"bg_color": "0x26878378",
|
|
"font_color": "0xffeb5757",
|
|
},
|
|
},
|
|
{"insert": "."},
|
|
],
|
|
);
|
|
});
|
|
|
|
// sample 6
|
|
// 1. Foo
|
|
// 2. Bar
|
|
// 3. Baz
|
|
test('sample 6', () {
|
|
const html = '''<ol>
|
|
<li>Foo</li>
|
|
<li>Bar</li>
|
|
<li>Baz</li>
|
|
</ol>''';
|
|
final document = htmlToDocument(html);
|
|
expect(document.nodeAtPath([0])!.type, NumberedListBlockKeys.type);
|
|
expect(document.nodeAtPath([0])!.delta!.toPlainText(), 'Foo');
|
|
expect(document.nodeAtPath([1])!.type, NumberedListBlockKeys.type);
|
|
expect(document.nodeAtPath([1])!.delta!.toPlainText(), 'Bar');
|
|
expect(document.nodeAtPath([2])!.type, NumberedListBlockKeys.type);
|
|
expect(document.nodeAtPath([2])!.delta!.toPlainText(), 'Baz');
|
|
});
|
|
|
|
test('sample 7', () {
|
|
const html = '''<ol>
|
|
<li>Foo
|
|
<ol>
|
|
<li>Bar
|
|
<ol>
|
|
<li>Baz</li>
|
|
</ol>
|
|
</li>
|
|
</ol>
|
|
</li>
|
|
</ol>''';
|
|
final document = htmlToDocument(html);
|
|
expect(document.root.children.length, 1);
|
|
final foo = document.nodeAtPath([0])!;
|
|
final bar = document.nodeAtPath([0, 0])!;
|
|
final baz = document.nodeAtPath([0, 0, 0])!;
|
|
expect(foo.type, NumberedListBlockKeys.type);
|
|
expect(foo.delta!.toPlainText(), 'Foo');
|
|
expect(bar.parent, foo);
|
|
expect(bar.type, NumberedListBlockKeys.type);
|
|
expect(bar.delta!.toPlainText(), 'Bar');
|
|
expect(baz.parent, bar);
|
|
expect(baz.type, NumberedListBlockKeys.type);
|
|
expect(baz.delta!.toPlainText(), 'Baz');
|
|
});
|
|
});
|
|
|
|
test('sample 8', () {
|
|
const html = '''<ol>
|
|
<li><strong>Foo</strong></li>
|
|
<li><em>Bar</em></li>
|
|
<li><s>Baz</s></li>
|
|
</ol>
|
|
<ul>
|
|
<li><strong>Foo</strong></li>
|
|
<li><em>Bar</em></li>
|
|
<li><s>Baz</s></li>
|
|
</ul>''';
|
|
final document = htmlToDocument(html);
|
|
expect(document.root.children.length, 6);
|
|
final foo1 = document.nodeAtPath([0])!;
|
|
final bar1 = document.nodeAtPath([1])!;
|
|
final baz1 = document.nodeAtPath([2])!;
|
|
final foo2 = document.nodeAtPath([3])!;
|
|
final bar2 = document.nodeAtPath([4])!;
|
|
final baz2 = document.nodeAtPath([5])!;
|
|
expect(foo1.type, NumberedListBlockKeys.type);
|
|
expect(foo1.delta!.toPlainText(), 'Foo');
|
|
expect(bar1.type, NumberedListBlockKeys.type);
|
|
expect(bar1.delta!.toPlainText(), 'Bar');
|
|
expect(baz1.type, NumberedListBlockKeys.type);
|
|
expect(baz1.delta!.toPlainText(), 'Baz');
|
|
expect(foo2.type, BulletedListBlockKeys.type);
|
|
expect(foo2.delta!.toPlainText(), 'Foo');
|
|
expect(bar2.type, BulletedListBlockKeys.type);
|
|
expect(bar2.delta!.toPlainText(), 'Bar');
|
|
expect(baz2.type, BulletedListBlockKeys.type);
|
|
expect(baz2.delta!.toPlainText(), 'Baz');
|
|
});
|
|
|
|
// copy from Notion
|
|
// There's a line with different formats, such as **bold**, __italic__, underline, ~~strikethrough~~, and `inline code`.
|
|
test('sample 9', () {
|
|
const html =
|
|
'''<p>Hello</p><p>There's a line with different formats, such as <strong>bold</strong>, <em>italic</em>, underline, <s>strikethrough</s>, and <code>inline code</code>.</p>''';
|
|
final document = htmlToDocument(html);
|
|
expect(document.root.children.length, 2);
|
|
final delta = document.nodeAtPath([1])!.delta!;
|
|
expect(
|
|
delta.toJson(),
|
|
[
|
|
{"insert": "There's a line with different formats, such as "},
|
|
{
|
|
"insert": "bold",
|
|
"attributes": {"bold": true},
|
|
},
|
|
{"insert": ", "},
|
|
{
|
|
"insert": "italic",
|
|
"attributes": {"italic": true},
|
|
},
|
|
{"insert": ", underline, "},
|
|
{
|
|
"insert": "strikethrough",
|
|
"attributes": {"strikethrough": true},
|
|
},
|
|
{"insert": ", and "},
|
|
{
|
|
"insert": "inline code",
|
|
"attributes": {"code": true},
|
|
},
|
|
{"insert": "."},
|
|
],
|
|
);
|
|
});
|
|
|
|
test('sample 10', () {
|
|
const html =
|
|
'''<meta charset='utf-8'><span style="color: rgb(36, 36, 36); font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">DTrace is a<span> </span></span><mark class="ael aco ao" style="box-sizing: inherit; cursor: pointer; color: currentcolor; background-color: rgb(187, 219, 186); font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><strong class="mq fp" style="box-sizing: inherit; font-weight: 700; font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif;"><em class="mp" style="box-sizing: inherit; font-style: italic;">dynamic tracing</em></strong></mark><mark class="ael aco ao" style="box-sizing: inherit; cursor: pointer; color: currentcolor; background-color: rgb(187, 219, 186); font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span> </span>technology</mark><span style="color: rgb(36, 36, 36); font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;"><span> </span>that can be used to locate<span> </span></span><mark class="acn aco ao" style="box-sizing: inherit; cursor: pointer; background-color: rgb(232, 243, 232); color: currentcolor; font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">system performance issues</mark><span style="color: rgb(36, 36, 36); font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">, obtain information about<span> </span></span><mark class="acn aco ao" style="box-sizing: inherit; cursor: pointer; background-color: rgb(232, 243, 232); color: currentcolor; font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">system function calls</mark><span style="color: rgb(36, 36, 36); font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">, or monitor system runtime information. And worth noting is that DTrace is<span> </span></span><mark class="acn aco ao" style="box-sizing: inherit; cursor: pointer; background-color: rgb(232, 243, 232); color: currentcolor; font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><strong class="mq fp" style="box-sizing: inherit; font-weight: 700; font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif;">non-intrusive</strong></mark><span style="color: rgb(36, 36, 36); font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;"><span> </span>to existing code. Also, there is no need to modify the existing code or use<span> </span></span><mark class="acn aco ao" style="box-sizing: inherit; cursor: pointer; background-color: rgb(232, 243, 232); color: currentcolor; font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">instrumentation technology</mark><span style="color: rgb(36, 36, 36); font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;"><span> </span>to obtain more system information.</span>''';
|
|
final document = htmlToDocument(html);
|
|
expect(document.root.children.length, 1);
|
|
final delta = document.nodeAtPath([0])!.delta!;
|
|
expect(
|
|
delta.toJson(),
|
|
[
|
|
{
|
|
"insert": "DTrace is a ",
|
|
"attributes": {"bg_color": "0xffffffff", "font_color": "0xff242424"},
|
|
},
|
|
{
|
|
"insert": "dynamic tracing",
|
|
"attributes": {
|
|
"bg_color": "0xffbbdbba",
|
|
"bold": true,
|
|
"italic": true,
|
|
},
|
|
},
|
|
{
|
|
"insert": " technology",
|
|
"attributes": {"bg_color": "0xffbbdbba"},
|
|
},
|
|
{
|
|
"insert": " that can be used to locate ",
|
|
"attributes": {"bg_color": "0xffffffff", "font_color": "0xff242424"},
|
|
},
|
|
{
|
|
"insert": "system performance issues",
|
|
"attributes": {"bg_color": "0xffe8f3e8"},
|
|
},
|
|
{
|
|
"insert": ", obtain information about ",
|
|
"attributes": {"bg_color": "0xffffffff", "font_color": "0xff242424"},
|
|
},
|
|
{
|
|
"insert": "system function calls",
|
|
"attributes": {"bg_color": "0xffe8f3e8"},
|
|
},
|
|
{
|
|
"insert":
|
|
", or monitor system runtime information. And worth noting is that DTrace is ",
|
|
"attributes": {"bg_color": "0xffffffff", "font_color": "0xff242424"},
|
|
},
|
|
{
|
|
"insert": "non-intrusive",
|
|
"attributes": {"bg_color": "0xffe8f3e8", "bold": true},
|
|
},
|
|
{
|
|
"insert":
|
|
" to existing code. Also, there is no need to modify the existing code or use ",
|
|
"attributes": {"bg_color": "0xffffffff", "font_color": "0xff242424"},
|
|
},
|
|
{
|
|
"insert": "instrumentation technology",
|
|
"attributes": {"bg_color": "0xffe8f3e8"},
|
|
},
|
|
{
|
|
"insert": " to obtain more system information.",
|
|
"attributes": {"bg_color": "0xffffffff", "font_color": "0xff242424"},
|
|
}
|
|
],
|
|
);
|
|
});
|
|
|
|
test('sample 11', () {
|
|
const html = '''
|
|
<h1>Heading 1</h1>
|
|
<h2>Heading 2</h2>
|
|
<h3>Heading 3</h3>
|
|
<h4>Heading 4</h4>
|
|
<h5>Heading 5</h5>
|
|
<h6>Heading 6</h6>
|
|
''';
|
|
final document = htmlToDocument(html);
|
|
for (var i = 1; i <= 6; i++) {
|
|
final node = document.nodeAtPath([i - 1]);
|
|
expect(node!.type, HeadingBlockKeys.type);
|
|
expect(node.delta!.toPlainText(), 'Heading $i');
|
|
expect(node.attributes[HeadingBlockKeys.level], i);
|
|
}
|
|
});
|
|
|
|
test('sample 12', () {
|
|
// Checkout conversion is too low: only 18% of users who click on “Book” checkout.
|
|
// Comparable funnels for hotel booking sites achieve ~30% (source).
|
|
const html =
|
|
'''<meta charset='utf-8'><meta charset="utf-8"><b style="font-weight:normal;" id="docs-internal-guid-30b67c3b-7fff-e5ec-0b19-376448d34980"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Checkout conversion is too low: only 18% of users who click on “Book” checkout.</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Comparable funnels for hotel booking sites achieve ~30% (</span><a href="https://docs.google.com/document/d/147-eAtY305IGAghvmQzn0NXUFlh2zQs50GbmBNlgnaA/edit?tab=t.0" style="text-decoration:none;"><span style="font-size:11pt;font-family:Arial,sans-serif;color:#1155cc;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:underline;-webkit-text-decoration-skip:none;text-decoration-skip-ink:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">source</span></a><span style="font-size:11pt;font-family:Arial,sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">).</span></p></b><br class="Apple-interchange-newline">''';
|
|
final document = htmlToDocument(html);
|
|
|
|
final node = document.nodeAtPath([0])!;
|
|
expect(node.type, ParagraphBlockKeys.type);
|
|
expect(
|
|
node.delta!.toPlainText(),
|
|
'Checkout conversion is too low: only 18% of users who click on “Book” checkout.',
|
|
);
|
|
|
|
final node2 = document.nodeAtPath([1])!;
|
|
expect(node2.type, ParagraphBlockKeys.type);
|
|
final jsonList = node2.delta!.toJson();
|
|
final cleanJson = jsonList.map((e) {
|
|
final map = e as Map;
|
|
map.removeWhere((k, v) => k != 'insert' && k != 'attributes');
|
|
|
|
return map;
|
|
}).toList();
|
|
expect(
|
|
cleanJson,
|
|
[
|
|
{
|
|
'insert': 'Comparable funnels for hotel booking sites achieve ~30% (',
|
|
'attributes': {'font_color': '0xff000000'},
|
|
},
|
|
{
|
|
'insert': 'source',
|
|
'attributes': {
|
|
'href':
|
|
'https://docs.google.com/document/d/147-eAtY305IGAghvmQzn0NXUFlh2zQs50GbmBNlgnaA/edit?tab=t.0',
|
|
'underline': true,
|
|
'font_color': '0xff1155cc',
|
|
},
|
|
},
|
|
{
|
|
'insert': ').',
|
|
'attributes': {'font_color': '0xff000000'},
|
|
}
|
|
],
|
|
);
|
|
});
|
|
}
|