Skip to content

Commit d124963

Browse files
committed
test: add service error 500 case, strengthen order assertion, drop batch_eligible from catalog
1 parent c48a30b commit d124963

6 files changed

Lines changed: 317 additions & 19 deletions

File tree

apps/api/services/text/spellcheck/transport_http_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,12 @@ func TestSpellcheckBatch_MixedTexts(t *testing.T) {
126126

127127
func TestSpellcheckBatch_OrderPreserved(t *testing.T) {
128128
t.Parallel()
129+
// No matches returned — so Corrected equals the original text for every
130+
// item, letting us assert that each result maps to the right input position.
129131
lt := newMockLT(t, []ltMatch{})
130132
defer lt.Close()
131133
r := setupRouter(lt.URL)
132134

133-
// RFC requires results to stay in the same order as the input array.
134135
body := `{"texts":["Hello world","Clean text","More clean text"]}`
135136
req := httptest.NewRequest(http.MethodPost, "/spellcheck/batch", strings.NewReader(body))
136137
req.Header.Set("Content-Type", "application/json")
@@ -142,6 +143,9 @@ func TestSpellcheckBatch_OrderPreserved(t *testing.T) {
142143
var resp httpx.Response[BatchCheckResponse]
143144
require.NoError(t, json.NewDecoder(w.Body).Decode(&resp))
144145
require.Len(t, resp.Data.Results, 3)
146+
assert.Equal(t, "Hello world", resp.Data.Results[0].Corrected)
147+
assert.Equal(t, "Clean text", resp.Data.Results[1].Corrected)
148+
assert.Equal(t, "More clean text", resp.Data.Results[2].Corrected)
145149
}
146150

147151
func TestSpellcheckBatch_UsageCountHeader(t *testing.T) {
@@ -222,3 +226,18 @@ func TestSpellcheckBatch_MissingBody(t *testing.T) {
222226

223227
assert.Equal(t, http.StatusBadRequest, w.Code)
224228
}
229+
230+
func TestSpellcheckBatch_ServiceError(t *testing.T) {
231+
t.Parallel()
232+
// Point the service at a port where nothing is listening so every
233+
// LanguageTool call fails, simulating an unreachable backend.
234+
r := setupRouter("http://localhost:19999")
235+
236+
body := `{"texts":["Hello world","Clean text"]}`
237+
req := httptest.NewRequest(http.MethodPost, "/spellcheck/batch", strings.NewReader(body))
238+
req.Header.Set("Content-Type", "application/json")
239+
w := httptest.NewRecorder()
240+
r.ServeHTTP(w, req)
241+
242+
assert.Equal(t, http.StatusInternalServerError, w.Code)
243+
}

apps/dashboard/config/api_catalog.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,6 @@ apis:
429429
- text
430430
description: Check spelling and get correction suggestions for misspelled words
431431
endpoints_count: 2
432-
batch_eligible: true
433432
status: live
434433
popular: true
435434
documentation_url: /apis/spell-check

apps/dashboard/config/api_docs/spell-check.yml

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ overview:
1111
- Form validation and input sanitisation
1212
- Educational platforms and grammar tools
1313
features:
14-
- Detects misspelled words using an English dictionary
15-
- Provides the best correction suggestion per misspelled word
14+
- Detects misspelled words and grammar issues using LanguageTool
15+
- Returns the best correction and up to 3 ranked alternative suggestions per misspelled word
1616
- Returns character positions for each correction
17-
- Preserves original capitalisation in suggestions
18-
- Only ASCII letter sequences are spell-checked; non-ASCII characters are passed through unchanged
17+
- Supports full Unicode input including accented and non-Latin characters
18+
- Batch endpoint processes up to 50 texts in a single request
1919
endpoints:
2020
- name: Check Spelling
2121
method: POST
@@ -37,9 +37,24 @@ endpoints:
3737
"data": {
3838
"corrected": "This is a simple test",
3939
"corrections": [
40-
{"original": "Ths", "suggested": "This", "position": 0},
41-
{"original": "smiple", "suggested": "simple", "position": 9},
42-
{"original": "tset", "suggested": "test", "position": 16}
40+
{
41+
"original": "Ths",
42+
"suggested": "This",
43+
"suggestions": ["Th's", "Th", "This"],
44+
"position": 0
45+
},
46+
{
47+
"original": "smiple",
48+
"suggested": "simple",
49+
"suggestions": ["simple", "smile", "Siple"],
50+
"position": 9
51+
},
52+
{
53+
"original": "tset",
54+
"suggested": "test",
55+
"suggestions": ["set", "test", "stet"],
56+
"position": 16
57+
}
4358
]
4459
},
4560
"metadata": {
@@ -49,12 +64,13 @@ endpoints:
4964
response_fields:
5065
- name: corrected
5166
type: string
52-
description: The full input text with all misspelled words replaced by their suggested corrections
67+
description: The full input text with all misspelled words replaced by the top-ranked suggestion
5368
- name: corrections
5469
type: array of objects
5570
description: >-
5671
List of individual corrections. Each item contains: original (the misspelled word), suggested (the
57-
correction), and position (0-based character offset in the original text)
72+
top-ranked replacement applied to corrected), suggestions (up to 3 ranked alternatives returned by
73+
LanguageTool, from most to least likely), and position (0-based Unicode character offset in the original text)
5874
errors:
5975
- code: validation_failed
6076
status: 422
@@ -135,14 +151,29 @@ endpoints:
135151
{
136152
"corrected": "This is a test",
137153
"corrections": [
138-
{"original": "Ths", "suggested": "This", "position": 0},
139-
{"original": "tset", "suggested": "test", "position": 9}
154+
{
155+
"original": "Ths",
156+
"suggested": "This",
157+
"suggestions": ["Th's", "Th", "This"],
158+
"position": 0
159+
},
160+
{
161+
"original": "tset",
162+
"suggested": "test",
163+
"suggestions": ["set", "test", "stet"],
164+
"position": 9
165+
}
140166
]
141167
},
142168
{
143169
"corrected": "Simple example",
144170
"corrections": [
145-
{"original": "Smiple", "suggested": "Simple", "position": 0}
171+
{
172+
"original": "Smiple",
173+
"suggested": "Simple",
174+
"suggestions": ["Simple", "Smile", "Siple"],
175+
"position": 0
176+
}
146177
]
147178
}
148179
],
@@ -155,7 +186,9 @@ endpoints:
155186
response_fields:
156187
- name: results
157188
type: array of objects
158-
description: One entry per input text, in the same order as the input array. Each item contains corrected (the fixed text) and corrections (list of individual corrections with original, suggested, and position).
189+
description: >-
190+
One entry per input text, in the same order as the input array. Each item contains corrected (the fixed
191+
text) and corrections (list of individual corrections with original, suggested, suggestions, and position).
159192
- name: total
160193
type: integer
161194
description: Number of texts processed. Equals the length of the input array.
@@ -219,17 +252,20 @@ endpoints:
219252
data['data']['results'].each { |item| puts item['corrected'] }
220253
faq:
221254
- question: What language does spell check support?
222-
answer: The spell checker currently supports English only.
255+
answer: The spell checker currently processes text as English (en-US). Multi-language support is planned for a future release.
223256
- question: Are positions zero-indexed?
224257
answer: >-
225258
Yes. The position field is a 0-based Unicode character (rune) offset in the original input string. This matches
226259
how Python, JavaScript, and Ruby index strings.
227260
- question: What happens if the text has no spelling mistakes?
228261
answer: "The corrected field will equal the input text and corrections will be an empty array: []."
229-
- question: Does capitalisation affect the correction?
262+
- question: What is the difference between suggested and suggestions?
230263
answer: >-
231-
No. Spell checking is case-insensitive. The suggested correction mirrors the capitalisation of the original word:
232-
a capitalised misspelling produces a capitalised suggestion.
264+
suggested is the single best replacement, already applied to the corrected text. suggestions is an ordered list
265+
of up to 3 alternatives returned by LanguageTool (from most to least likely), which you can use to present a
266+
correction picker to your users instead of applying the first option automatically.
267+
- question: How many items can I send in a batch request?
268+
answer: Between 1 and 50 texts per request. Requests with an empty array or more than 50 items return 422.
233269
performance:
234270
p50_ms: 807
235271
p95_ms: 1147

0 commit comments

Comments
 (0)