mirror of
https://github.com/flutter/packages.git
synced 2025-06-30 23:03:11 +08:00
Fixed table last row empty bug (#296)
This commit is contained in:
@ -219,6 +219,15 @@ class MarkdownBuilder implements md.NodeVisitor {
|
||||
|
||||
_addParentInlineIfNeeded(_blocks.last.tag);
|
||||
|
||||
// The Markdown parser passes empty table data tags for blank
|
||||
// table cells. Insert a text node with an empty string in this
|
||||
// case for the table cell to get properly created.
|
||||
if (element.tag == 'td' &&
|
||||
element.children != null &&
|
||||
element.children.isEmpty) {
|
||||
element.children.add(md.Text(''));
|
||||
}
|
||||
|
||||
TextStyle parentStyle = _inlines.last.style;
|
||||
_inlines.add(_InlineElement(
|
||||
tag,
|
||||
|
@ -120,5 +120,410 @@ void defineTests() {
|
||||
expect(table.defaultColumnWidth, columnWidth);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'table with last row of empty table cells',
|
||||
(WidgetTester tester) async {
|
||||
final ThemeData theme =
|
||||
ThemeData.light().copyWith(textTheme: textTheme);
|
||||
|
||||
const String data = '|Header 1|Header 2|\n|----|----|\n| | |';
|
||||
const FixedColumnWidth columnWidth = FixedColumnWidth(100);
|
||||
final MarkdownStyleSheet style =
|
||||
MarkdownStyleSheet.fromTheme(theme).copyWith(
|
||||
tableColumnWidth: columnWidth,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
boilerplate(MarkdownBody(data: data, styleSheet: style)));
|
||||
|
||||
final Table table = tester.widget(find.byType(Table));
|
||||
|
||||
expectTableSize(2, 2);
|
||||
|
||||
expect(find.byType(RichText), findsNWidgets(4));
|
||||
List<String> cellText = find
|
||||
.byType(RichText)
|
||||
.evaluate()
|
||||
.map((e) => e.widget)
|
||||
.cast<RichText>()
|
||||
.map((richText) => richText.text)
|
||||
.cast<TextSpan>()
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
expect(cellText[0], 'Header 1');
|
||||
expect(cellText[1], 'Header 2');
|
||||
expect(cellText[2], '');
|
||||
expect(cellText[3], '');
|
||||
|
||||
expect(table.defaultColumnWidth, columnWidth);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'table with an empty row an last row has an empty table cell',
|
||||
(WidgetTester tester) async {
|
||||
final ThemeData theme =
|
||||
ThemeData.light().copyWith(textTheme: textTheme);
|
||||
|
||||
const String data =
|
||||
'|Header 1|Header 2|\n|----|----|\n| | |\n| bar | |';
|
||||
const FixedColumnWidth columnWidth = FixedColumnWidth(100);
|
||||
final MarkdownStyleSheet style =
|
||||
MarkdownStyleSheet.fromTheme(theme).copyWith(
|
||||
tableColumnWidth: columnWidth,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
boilerplate(MarkdownBody(data: data, styleSheet: style)));
|
||||
|
||||
final Table table = tester.widget(find.byType(Table));
|
||||
|
||||
expectTableSize(3, 2);
|
||||
|
||||
expect(find.byType(RichText), findsNWidgets(6));
|
||||
List<String> cellText = find
|
||||
.byType(RichText)
|
||||
.evaluate()
|
||||
.map((e) => e.widget)
|
||||
.cast<RichText>()
|
||||
.map((richText) => richText.text)
|
||||
.cast<TextSpan>()
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
expect(cellText[0], 'Header 1');
|
||||
expect(cellText[1], 'Header 2');
|
||||
expect(cellText[2], '');
|
||||
expect(cellText[3], '');
|
||||
expect(cellText[4], 'bar');
|
||||
expect(cellText[5], '');
|
||||
|
||||
expect(table.defaultColumnWidth, columnWidth);
|
||||
},
|
||||
);
|
||||
|
||||
group('GFM Examples', () {
|
||||
testWidgets(
|
||||
// Example 198 from GFM.
|
||||
'simple table',
|
||||
(WidgetTester tester) async {
|
||||
final ThemeData theme =
|
||||
ThemeData.light().copyWith(textTheme: textTheme);
|
||||
|
||||
const String data = '| foo | bar |\n| --- | --- |\n| baz | bim |';
|
||||
const FixedColumnWidth columnWidth = FixedColumnWidth(100);
|
||||
final MarkdownStyleSheet style =
|
||||
MarkdownStyleSheet.fromTheme(theme).copyWith(
|
||||
tableColumnWidth: columnWidth,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
boilerplate(MarkdownBody(data: data, styleSheet: style)));
|
||||
|
||||
final Table table = tester.widget(find.byType(Table));
|
||||
|
||||
expectTableSize(2, 2);
|
||||
|
||||
expect(find.byType(RichText), findsNWidgets(4));
|
||||
List<String> cellText = find
|
||||
.byType(RichText)
|
||||
.evaluate()
|
||||
.map((e) => e.widget)
|
||||
.cast<RichText>()
|
||||
.map((richText) => richText.text)
|
||||
.cast<TextSpan>()
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
expect(cellText[0], 'foo');
|
||||
expect(cellText[1], 'bar');
|
||||
expect(cellText[2], 'baz');
|
||||
expect(cellText[3], 'bim');
|
||||
expect(table.defaultColumnWidth, columnWidth);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
// Example 199 from GFM.
|
||||
'input table cell data does not need to match column length',
|
||||
(WidgetTester tester) async {
|
||||
final ThemeData theme =
|
||||
ThemeData.light().copyWith(textTheme: textTheme);
|
||||
|
||||
const String data = '| abc | defghi |\n:-: | -----------:\nbar | baz';
|
||||
const FixedColumnWidth columnWidth = FixedColumnWidth(100);
|
||||
final MarkdownStyleSheet style =
|
||||
MarkdownStyleSheet.fromTheme(theme).copyWith(
|
||||
tableColumnWidth: columnWidth,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
boilerplate(MarkdownBody(data: data, styleSheet: style)));
|
||||
|
||||
final Table table = tester.widget(find.byType(Table));
|
||||
|
||||
expectTableSize(2, 2);
|
||||
|
||||
expect(find.byType(RichText), findsNWidgets(4));
|
||||
List<String> cellText = find
|
||||
.byType(RichText)
|
||||
.evaluate()
|
||||
.map((e) => e.widget)
|
||||
.cast<RichText>()
|
||||
.map((richText) => richText.text)
|
||||
.cast<TextSpan>()
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
expect(cellText[0], 'abc');
|
||||
expect(cellText[1], 'defghi');
|
||||
expect(cellText[2], 'bar');
|
||||
expect(cellText[3], 'baz');
|
||||
expect(table.defaultColumnWidth, columnWidth);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
// Example 200 from GFM.
|
||||
'include a pipe in table cell data by escaping the pipe',
|
||||
(WidgetTester tester) async {
|
||||
final ThemeData theme =
|
||||
ThemeData.light().copyWith(textTheme: textTheme);
|
||||
|
||||
const String data =
|
||||
'| f\|oo |\n| ------ |\n| b `\|` az |\n| b **\|** im |';
|
||||
const FixedColumnWidth columnWidth = FixedColumnWidth(100);
|
||||
final MarkdownStyleSheet style =
|
||||
MarkdownStyleSheet.fromTheme(theme).copyWith(
|
||||
tableColumnWidth: columnWidth,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
boilerplate(MarkdownBody(data: data, styleSheet: style)));
|
||||
|
||||
final Table table = tester.widget(find.byType(Table));
|
||||
|
||||
expectTableSize(1, 3);
|
||||
|
||||
expect(find.byType(RichText), findsNWidgets(4));
|
||||
List<String> cellText = find
|
||||
.byType(RichText)
|
||||
.evaluate()
|
||||
.map((e) => e.widget)
|
||||
.cast<RichText>()
|
||||
.map((richText) => richText.text)
|
||||
.cast<TextSpan>()
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
expect(cellText[0], 'f|oo');
|
||||
expect(cellText[1], 'defghi');
|
||||
expect(cellText[2], 'b | az');
|
||||
expect(cellText[3], 'b | im');
|
||||
expect(table.defaultColumnWidth, columnWidth);
|
||||
},
|
||||
// TODO(mjordan56) Remove skip once the issue #340 in the markdown package
|
||||
// is fixed and released. https://github.com/dart-lang/markdown/issues/340
|
||||
// This test will need adjusting once issue #340 is fixed.
|
||||
skip: true,
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
// Example 201 from GFM.
|
||||
'table definition is complete at beginning of new block',
|
||||
(WidgetTester tester) async {
|
||||
final ThemeData theme =
|
||||
ThemeData.light().copyWith(textTheme: textTheme);
|
||||
|
||||
const String data =
|
||||
'| abc | def |\n| --- | --- |\n| bar | baz |\n> bar';
|
||||
const FixedColumnWidth columnWidth = FixedColumnWidth(100);
|
||||
final MarkdownStyleSheet style =
|
||||
MarkdownStyleSheet.fromTheme(theme).copyWith(
|
||||
tableColumnWidth: columnWidth,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
boilerplate(MarkdownBody(data: data, styleSheet: style)));
|
||||
|
||||
final Table table = tester.widget(find.byType(Table));
|
||||
|
||||
expectTableSize(2, 2);
|
||||
|
||||
expect(find.byType(RichText), findsNWidgets(5));
|
||||
List<String> text = find
|
||||
.byType(RichText)
|
||||
.evaluate()
|
||||
.map((e) => e.widget)
|
||||
.cast<RichText>()
|
||||
.map((richText) => richText.text)
|
||||
.cast<TextSpan>()
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
expect(text[0], 'abc');
|
||||
expect(text[1], 'def');
|
||||
expect(text[2], 'bar');
|
||||
expect(text[3], 'baz');
|
||||
expect(table.defaultColumnWidth, columnWidth);
|
||||
|
||||
// Blockquote
|
||||
expect(find.byType(DecoratedBox), findsOneWidget);
|
||||
expect(text[4], 'bar');
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
// Example 202 from GFM.
|
||||
'table definition is complete at first empty line',
|
||||
(WidgetTester tester) async {
|
||||
final ThemeData theme =
|
||||
ThemeData.light().copyWith(textTheme: textTheme);
|
||||
|
||||
const String data =
|
||||
'| abc | def |\n| --- | --- |\n| bar | baz |\nbar\n\nbar';
|
||||
const FixedColumnWidth columnWidth = FixedColumnWidth(100);
|
||||
final MarkdownStyleSheet style =
|
||||
MarkdownStyleSheet.fromTheme(theme).copyWith(
|
||||
tableColumnWidth: columnWidth,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
boilerplate(MarkdownBody(data: data, styleSheet: style)));
|
||||
|
||||
final Table table = tester.widget(find.byType(Table));
|
||||
|
||||
expectTableSize(3, 2);
|
||||
|
||||
expect(find.byType(RichText), findsNWidgets(6));
|
||||
List<String> text = find
|
||||
.byType(RichText)
|
||||
.evaluate()
|
||||
.map((e) => e.widget)
|
||||
.cast<RichText>()
|
||||
.map((richText) => richText.text)
|
||||
.cast<TextSpan>()
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
expect(text[0], 'abc');
|
||||
expect(text[1], 'def');
|
||||
expect(text[2], 'bar');
|
||||
expect(text[3], 'baz');
|
||||
expect(text[4], 'bar');
|
||||
expect(table.defaultColumnWidth, columnWidth);
|
||||
|
||||
// Paragraph text
|
||||
expect(text[5], 'bar');
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
// Example 203 from GFM.
|
||||
'table header row must match the delimiter row in number of cells',
|
||||
(WidgetTester tester) async {
|
||||
final ThemeData theme =
|
||||
ThemeData.light().copyWith(textTheme: textTheme);
|
||||
|
||||
const String data = '| abc | def |\n| --- |\n| bar |';
|
||||
const FixedColumnWidth columnWidth = FixedColumnWidth(100);
|
||||
final MarkdownStyleSheet style =
|
||||
MarkdownStyleSheet.fromTheme(theme).copyWith(
|
||||
tableColumnWidth: columnWidth,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
boilerplate(MarkdownBody(data: data, styleSheet: style)));
|
||||
|
||||
expect(find.byType(Table), findsNothing);
|
||||
List<String> text = find
|
||||
.byType(RichText)
|
||||
.evaluate()
|
||||
.map((e) => e.widget)
|
||||
.cast<RichText>()
|
||||
.map((richText) => richText.text)
|
||||
.cast<TextSpan>()
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
expect(text[0], '| abc | def | | --- | | bar |');
|
||||
},
|
||||
// TODO(mjordan56) Remove skip once the issue #341 in the markdown package
|
||||
// is fixed and released. https://github.com/dart-lang/markdown/issues/341
|
||||
skip: true,
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
// Example 204 from GFM.
|
||||
'remainder of table cells may vary, excess cells are ignored',
|
||||
(WidgetTester tester) async {
|
||||
final ThemeData theme =
|
||||
ThemeData.light().copyWith(textTheme: textTheme);
|
||||
|
||||
const String data =
|
||||
'| abc | def |\n| --- | --- |\n| bar |\n| bar | baz | boo |';
|
||||
const FixedColumnWidth columnWidth = FixedColumnWidth(100);
|
||||
final MarkdownStyleSheet style =
|
||||
MarkdownStyleSheet.fromTheme(theme).copyWith(
|
||||
tableColumnWidth: columnWidth,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
boilerplate(MarkdownBody(data: data, styleSheet: style)));
|
||||
|
||||
final Table table = tester.widget(find.byType(Table));
|
||||
|
||||
expectTableSize(3, 2);
|
||||
|
||||
expect(find.byType(RichText), findsNWidgets(5));
|
||||
List<String> cellText = find
|
||||
.byType(RichText)
|
||||
.evaluate()
|
||||
.map((e) => e.widget)
|
||||
.cast<RichText>()
|
||||
.map((richText) => richText.text)
|
||||
.cast<TextSpan>()
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
expect(cellText[0], 'abc');
|
||||
expect(cellText[1], 'def');
|
||||
expect(cellText[2], 'bar');
|
||||
expect(cellText[3], 'bar');
|
||||
expect(cellText[4], 'baz');
|
||||
expect(table.defaultColumnWidth, columnWidth);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
// Example 205 from GFM.
|
||||
'no table body is created when no rows are defined',
|
||||
(WidgetTester tester) async {
|
||||
final ThemeData theme =
|
||||
ThemeData.light().copyWith(textTheme: textTheme);
|
||||
|
||||
const String data = '| abc | def |\n| --- | --- |';
|
||||
const FixedColumnWidth columnWidth = FixedColumnWidth(100);
|
||||
final MarkdownStyleSheet style =
|
||||
MarkdownStyleSheet.fromTheme(theme).copyWith(
|
||||
tableColumnWidth: columnWidth,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
boilerplate(MarkdownBody(data: data, styleSheet: style)));
|
||||
|
||||
final Table table = tester.widget(find.byType(Table));
|
||||
|
||||
expectTableSize(1, 2);
|
||||
|
||||
expect(find.byType(RichText), findsNWidgets(2));
|
||||
List<String> cellText = find
|
||||
.byType(RichText)
|
||||
.evaluate()
|
||||
.map((e) => e.widget)
|
||||
.cast<RichText>()
|
||||
.map((richText) => richText.text)
|
||||
.cast<TextSpan>()
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
expect(cellText[0], 'abc');
|
||||
expect(cellText[1], 'def');
|
||||
expect(table.defaultColumnWidth, columnWidth);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -135,6 +135,17 @@ void expectInvalidLink(String linkText) {
|
||||
expect(textSpan.recognizer, isNull);
|
||||
}
|
||||
|
||||
void expectTableSize(int rows, int columns) {
|
||||
final tableFinder = find.byType(Table);
|
||||
expect(tableFinder, findsOneWidget);
|
||||
final table = tableFinder.evaluate().first.widget as Table;
|
||||
|
||||
expect(table.children.length, rows);
|
||||
for (int index = 0; index < rows; index++) {
|
||||
expect(table.children[index].children.length, columns);
|
||||
}
|
||||
}
|
||||
|
||||
void expectLinkTap(MarkdownLink actual, MarkdownLink expected) {
|
||||
expect(actual, equals(expected),
|
||||
reason:
|
||||
|
Reference in New Issue
Block a user