fix(app): Look up tags a word as the dictionary screen does

A vocabulary card filled through Look up in the composer got the word but
none of its tags, while the dictionary screen tags every word with its
JLPT level and word class. Both now take the tags from the word itself
(DictionaryWord.tagNames). Looking another word up on the same card swaps
the tags the word before brought; tags the person gave the card stay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-09 11:40:03 +02:00
commit d67dc8aa70
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -442,6 +442,82 @@ void main() {
expect(state.byId('copy')!.status, CardDraftStatus.dirty);
});
group('A word looked up', () {
CardContent word(String headword) => card(
headword,
'',
).copyWith(type: CardType.vocabulary, meanings: const ['a meaning']);
Future<Set<String>> namesOf(CardComposerState state) async {
final tagging = await tags.read();
return {
for (final id in state.byId('new')!.tagIds) tagging.byId(id)!.name,
};
}
test("fills the card and gives it the word's tags, made where "
'missing, and saved with it', () async {
final noun = await tags.create('Noun');
start();
await loaded();
bloc
..add(const CardComposerEventDraftAdded('new'))
..add(
CardComposerEventLookedUp('new', word('食べる'), const [
'JLPT-N5',
'Verb',
'Noun',
]),
);
final state = await until((s) => s.byId('new')?.tagIds.length == 3);
expect(state.byId('new')!.content.front, text('食べる'));
expect(await namesOf(state), {'JLPT-N5', 'Verb', 'Noun'});
expect(state.byId('new')!.tagIds, contains(noun));
bloc.add(const CardComposerEventLeft('new'));
final saved = await until(
(s) => s.byId('new')?.status == CardDraftStatus.saved,
);
final tagging = await tags.read();
expect(
{for (final tag in tagging.of(saved.byId('new')!.cardId!)) tag.name},
{'JLPT-N5', 'Verb', 'Noun'},
);
});
test('again swaps the tags the word before brought, and keeps the '
"person's own", () async {
final mine = await tags.create('Food');
final verb = await tags.create('Verb');
start();
await loaded();
bloc
..add(const CardComposerEventDraftAdded('new'))
..add(CardComposerEventTagsChanged('new', {mine, verb}))
..add(
CardComposerEventLookedUp('new', word('食べる'), const [
'JLPT-N5',
'Verb',
]),
);
await until((s) => s.byId('new')?.tagIds.length == 3);
final level = (await tags.read()).named('JLPT-N5')!.id;
bloc.add(
CardComposerEventLookedUp('new', word('寿司'), const ['Noun']),
);
final swapped = await until(
(s) => !(s.byId('new')?.tagIds.contains(level) ?? true),
);
expect(swapped.byId('new')!.content.front, text('寿司'));
// Verb was the person's before the first word came, so it stays.
expect(await namesOf(swapped), {'Food', 'Verb', 'Noun'});
});
});
test('clearing empties the fields and keeps the type', () async {
start();
await loaded();