Adds test for configurable hint foundries (See #10306)
Change-Id: Ib193d7c053e37e214f4f2be288fe079df744f2d4
diff --git a/Changes b/Changes
index 85ff5e7..fcf47d5 100644
--- a/Changes
+++ b/Changes
@@ -4,12 +4,13 @@
- Enhance handling of improper json files (diewald)
- Support API version 1.1 (diewald)
- Support title change in button groups (diewald)
- - Eliminates authorized_only (deprecation in API version 1.1)
+ - Eliminates authorized_only (deprecation in API version 1.1) (hebasta)
- Add 'glimpse' option to query panel (diewald)
- Fix test suite for glimpse-rearrangement (diewald)
- Mark "notinindex"-fields (diewald)
- Fix test suite for "allow-same-origin" sandbox rule (diewald)
- Escape commas and asterisks in query-by-match query creator (kupietz, hebasta)
+ - Tests for configurable hint foundries added (hebasta)
0.64 2026-02-14
- Improve 'Plugins' mounting (diewald)
diff --git a/dev/js/spec/hintSpec.js b/dev/js/spec/hintSpec.js
index 3b07bd9..31f48ee 100644
--- a/dev/js/spec/hintSpec.js
+++ b/dev/js/spec/hintSpec.js
@@ -1,6 +1,6 @@
"use strict";
-define(['hint', 'hint/input', 'hint/contextanalyzer', 'hint/menu', 'hint/item'], function (hintClass, inputClass, contextClass, menuClass, menuItemClass) {
+define(['hint', 'hint/input', 'hint/contextanalyzer', 'hint/menu', 'hint/item', 'hint/foundries'], function (hintClass, inputClass, contextClass, menuClass, menuItemClass, foundriesClass) {
function emitKeyboardEvent (element, type, letter, keyCode) {
// event type : keydown, keyup, keypress
@@ -67,6 +67,7 @@
};
};
};
+
KorAP.API.getMatchInfo = undefined;
KorAP.context = undefined;
// KorAP.annotationHelper = undefined;
@@ -227,7 +228,7 @@
expect(hint).toBeTruthy();
});
-
+
it('should alert at char pos', function () {
var hint = hintClass.create({
inputField : input
@@ -509,7 +510,64 @@
expect(menu.container().element().classList.contains("visible")).toBeFalsy();
});
+ it('should filter available foundries based on configuration', function () {
+
+ KorAP.annotationHelper["-"] = [
+ ["Base Annotation", "base/s=", "Structure"],
+ ["CoreNLP", "corenlp/", "Constituency, Named Entities, Part-of-Speech"],
+ ["TreeTagger", "tt/", "Lemma, Part-of-Speech"]
+ ];
+ KorAP.annotationHelper.filterByConfig();
+ let foundries = KorAP.annotationHelper["-"].map(e => e[1]);
+ expect(foundries).toContain("base/s=");
+ expect(foundries).toContain("corenlp/");
+ expect(foundries).toContain("tt/");
+
+ //set configuration to corenlp and tt
+ document.body.setAttribute('data-hint-foundries', 'corenlp,tt');
+ KorAP.annotationHelper.filterByConfig();
+ foundries = KorAP.annotationHelper["-"].map(e => e[1]);
+ expect(foundries).not.toContain("base/s=");
+ expect(foundries).toContain("corenlp/");
+ expect(foundries).toContain("tt/");
+
+ //set configuration to corenlp only, with different case and whitespaces
+ document.body.setAttribute('data-hint-foundries', ' coREnlp');
+ KorAP.annotationHelper.filterByConfig();
+ foundries = KorAP.annotationHelper["-"].map(e => e[1]);
+ expect(foundries).not.toContain("base/s=");
+ expect(foundries).toContain("corenlp/");
+ expect(foundries).not.toContain("tt/");
+
+ //Clean up
+ document.body.removeAttribute('data-hint-foundries');
+ });
+
+ it('should apply configured foundry filter if initialized', function () {
+
+ KorAP.annotationHelper["-"] = [
+ ["Base Annotation", "base/s=", "Structure"],
+ ["CoreNLP", "corenlp/", "Constituency, Named Entities, Part-of-Speech"],
+ ["TreeTagger", "tt/", "Lemma, Part-of-Speech"]
+ ];
+
+ document.body.setAttribute('data-hint-foundries', 'tt');
+
+ var hint = hintClass.create({
+ inputField : input
+ });
+ expect(hint).toBeTruthy();
+
+ let foundries = KorAP.annotationHelper["-"].map(e => e[1]);
+ expect(foundries).not.toContain("base/s=");
+ expect(foundries).not.toContain("corenlp/");
+ expect(foundries).toContain("tt/");
+
+ //Clean up
+ document.body.removeAttribute('data-hint-foundries');
+ });
+
xit('should remove all menus on escape');
});
diff --git a/t/hint_foundries.t b/t/hint_foundries.t
new file mode 100644
index 0000000..e427bdf
--- /dev/null
+++ b/t/hint_foundries.t
@@ -0,0 +1,165 @@
+use Mojo::Base -strict;
+use Test::More;
+use Test::Mojo;
+
+# Test 1: Default foundries (no configuration)
+subtest 'Default foundries' => sub {
+ my $t = Test::Mojo->new('Kalamar');
+
+ my $defaults = $t->app->defaults('hint_foundries');
+ is_deeply(
+ $defaults,
+ [qw(base corenlp dereko malt marmot opennlp spacy tt)],
+ 'Default foundries are set correctly'
+ );
+
+ # Check that data-hint-foundries is rendered in HTML
+ $t->get_ok('/')
+ ->status_is(200)
+ ->attr_like('body', 'data-hint-foundries', qr/base/)
+ ->attr_like('body', 'data-hint-foundries', qr/corenlp/)
+ ->attr_like('body', 'data-hint-foundries', qr/spacy/);
+};
+
+
+# Test 2: Custom foundries via config (inclusions only)
+subtest 'Custom foundries via config' => sub {
+ my $t = Test::Mojo->new('Kalamar' => {
+ Kalamar => {
+ hint_foundries => ['base', 'marmot', 'tt']
+ }
+ });
+
+ my $defaults = $t->app->defaults('hint_foundries');
+ is_deeply(
+ $defaults,
+ ['base', 'marmot', 'tt'],
+ 'Custom foundries are set correctly'
+ );
+
+ $t->get_ok('/')
+ ->status_is(200)
+ ->attr_like('body', 'data-hint-foundries', qr/base/)
+ ->attr_like('body', 'data-hint-foundries', qr/marmot/)
+ ->attr_like('body', 'data-hint-foundries', qr/tt/)
+ ->attr_unlike('body', 'data-hint-foundries', qr/corenlp/)
+ ->attr_unlike('body', 'data-hint-foundries', qr/spacy/);
+};
+
+
+# Test 3: Exclusions via config (e.g., -spacy, -corenlp)
+subtest 'Exclusions via config' => sub {
+ my $t = Test::Mojo->new('Kalamar' => {
+ Kalamar => {
+ hint_foundries => ['-spacy', '-corenlp']
+ }
+ });
+
+ my $defaults = $t->app->defaults('hint_foundries');
+
+ # Should contain all defaults except spacy and corenlp
+ ok((grep { $_ eq 'base' } @$defaults), 'Contains base');
+ ok((grep { $_ eq 'dereko' } @$defaults), 'Contains dereko');
+ ok((grep { $_ eq 'malt' } @$defaults), 'Contains malt');
+ ok((grep { $_ eq 'marmot' } @$defaults), 'Contains marmot');
+ ok((grep { $_ eq 'opennlp' } @$defaults), 'Contains opennlp');
+ ok((grep { $_ eq 'tt' } @$defaults), 'Contains tt');
+ ok(!(grep { $_ eq 'spacy' } @$defaults), 'Does not contain spacy');
+ ok(!(grep { $_ eq 'corenlp' } @$defaults), 'Does not contain corenlp');
+
+ $t->get_ok('/')
+ ->status_is(200)
+ ->attr_like('body', 'data-hint-foundries', qr/base/)
+ ->attr_unlike('body', 'data-hint-foundries', qr/spacy/)
+ ->attr_unlike('body', 'data-hint-foundries', qr/corenlp/);
+};
+
+
+# Test 4: Environment variable KALAMAR_HINT_FOUNDRIES
+subtest 'Environment variable' => sub {
+ local $ENV{KALAMAR_HINT_FOUNDRIES} = 'base,tt,marmot';
+
+ my $t = Test::Mojo->new('Kalamar');
+
+ my $defaults = $t->app->defaults('hint_foundries');
+ is_deeply(
+ $defaults,
+ ['base', 'tt', 'marmot'],
+ 'Foundries from environment variable'
+ );
+
+ $t->get_ok('/')
+ ->status_is(200)
+ ->attr_like('body', 'data-hint-foundries', qr/base,tt,marmot/);
+};
+
+
+# Test 5: Environment variable with exclusions
+subtest 'Environment variable with exclusions' => sub {
+ local $ENV{KALAMAR_HINT_FOUNDRIES} = '-spacy,-opennlp';
+
+ my $t = Test::Mojo->new('Kalamar');
+
+ my $defaults = $t->app->defaults('hint_foundries');
+
+ ok((grep { $_ eq 'base' } @$defaults), 'Contains base');
+ ok((grep { $_ eq 'corenlp' } @$defaults), 'Contains corenlp');
+ ok(!(grep { $_ eq 'spacy' } @$defaults), 'Does not contain spacy');
+ ok(!(grep { $_ eq 'opennlp' } @$defaults), 'Does not contain opennlp');
+};
+
+
+# Test 6: Environment variable overrides config
+subtest 'Environment variable overrides config' => sub {
+ local $ENV{KALAMAR_HINT_FOUNDRIES} = 'base,tt';
+
+ my $t = Test::Mojo->new('Kalamar' => {
+ Kalamar => {
+ hint_foundries => ['corenlp', 'marmot', 'spacy']
+ }
+ });
+
+ my $defaults = $t->app->defaults('hint_foundries');
+ is_deeply(
+ $defaults,
+ ['base', 'tt'],
+ 'Environment variable takes precedence over config'
+ );
+};
+
+
+# Test 7: Empty config foundries array uses defaults
+subtest 'Empty config uses defaults' => sub {
+ my $t = Test::Mojo->new('Kalamar' => {
+ Kalamar => {
+ hint_foundries => []
+ }
+ });
+
+ my $defaults = $t->app->defaults('hint_foundries');
+ is_deeply(
+ $defaults,
+ [qw(base corenlp dereko malt marmot opennlp spacy tt)],
+ 'Empty array results in defaults'
+ );
+};
+
+
+# Test 8: Case insensitivity of exclusions
+subtest 'Case insensitive exclusions' => sub {
+ my $t = Test::Mojo->new('Kalamar' => {
+ Kalamar => {
+ hint_foundries => ['-SPACY', '-CoreNLP']
+ }
+ });
+
+ my $defaults = $t->app->defaults('hint_foundries');
+
+ ok(!(grep { lc($_) eq 'spacy' } @$defaults), 'Does not contain spacy (case insensitive)');
+ ok(!(grep { lc($_) eq 'corenlp' } @$defaults), 'Does not contain corenlp (case insensitive)');
+ ok((grep { $_ eq 'base' } @$defaults), 'Still contains base');
+};
+
+
+done_testing;
+__END__