blob: 21c1eb83a9ecb71aae95a337a07ff928900703e5 [file] [log] [blame]
Marc Kupietz55fc3162022-12-04 16:25:49 +01001const chai = require('chai');
2const assert = chai.assert;
Marc Kupietz5e45a2f2022-12-03 15:32:40 +01003
4class KorAPRC {
5 korap_url = ""
6
7 constructor(korap_url) {
8 this.korap_url = korap_url
9 }
10
11 static new(korap_url) {
12 return new KorAPRC(korap_url)
13 }
14
15 async login(page, username, password) {
Marc Kupietz9e0f5192025-03-09 12:12:16 +010016 page.goto(this.korap_url);
17 await page.waitForNavigation({ waitUntil: 'networkidle2' });
Marc Kupietz55fc3162022-12-04 16:25:49 +010018 if (this.login == "") return false;
Marc Kupietz9e0f5192025-03-09 12:12:16 +010019 if (username == "") return false;
20 if (password == "") return false;
Marc Kupietz5e45a2f2022-12-03 15:32:40 +010021
Marc Kupietz9e0f5192025-03-09 12:12:16 +010022 await page.click('.dropdown-btn');
23 await page.waitForSelector('input[name=handle_or_email]', { visible: true });
24 const username_field = await page.$("input[name=handle_or_email]")
Marc Kupietz5e45a2f2022-12-03 15:32:40 +010025 if (username_field != null) {
Marc Kupietz9e0f5192025-03-09 12:12:16 +010026 await username_field.focus();
Marc Kupietz5e45a2f2022-12-03 15:32:40 +010027 await username_field.type(username);
Marc Kupietz9e0f5192025-03-09 12:12:16 +010028 const password_field = await page.$("input[name=pwd]")
29 await password_field.focus()
Marc Kupietz5e45a2f2022-12-03 15:32:40 +010030 await page.keyboard.type(password)
31 await page.keyboard.press("Enter")
Marc Kupietze533ca82022-12-06 07:53:22 +010032 } else {
33 return false
Marc Kupietz5e45a2f2022-12-03 15:32:40 +010034 }
35
Marc Kupietz9e0f5192025-03-09 12:12:16 +010036 await page.waitForNavigation({ waitUntil: 'networkidle2' });
37 const logout = await page.$(".logout")
Marc Kupietz5e45a2f2022-12-03 15:32:40 +010038 if (logout == null) {
39 return false
40 }
41
Marc Kupietz5e45a2f2022-12-03 15:32:40 +010042 return true
43 }
44
45 async search(page, query) {
Marc Kupietz9e0f5192025-03-09 12:12:16 +010046 const query_field = await page.$("#q-field");
47 assert.notEqual(query_field, null, "Query field not found");
48
49 await page.waitForSelector("#q-field", { visible: true });
50 await query_field.click({ clickCount: 3 });
51 await page.keyboard.type(query);
52 await page.keyboard.press("Enter");
53
54 await page.waitForNavigation({ waitUntil: 'networkidle2' });
Marc Kupietz9e0f5192025-03-09 12:12:16 +010055
Marc Kupietz964e7772025-06-03 15:02:30 +020056 // Wait for search results to be fully loaded
57 try {
58 await page.waitForSelector('ol li, #resultinfo, .result-item', {
59 visible: true,
60 timeout: 15000
61 });
62 // Give additional time for the results count to be populated
63 await new Promise(resolve => setTimeout(resolve, 2000));
64 } catch (error) {
65 // Continue if timeout, fallback methods will handle it
66 }
67
68 const resultsInfo = await page.evaluate(() => {
69 // Check common selectors for result counts
70 const selectors = [
71 '#total-results',
72 '#resultinfo',
73 '.result-count',
74 '.total-results',
75 '[data-results]',
76 '.found'
77 ];
78
79 for (const selector of selectors) {
80 const element = document.querySelector(selector);
81 if (element) {
82 const text = element.textContent || element.innerText || '';
83 const numbers = text.match(/\d+/g);
84 if (numbers && numbers.length > 0) {
85 return {
86 selector: selector,
87 numbers: numbers
88 };
89 }
90 }
91 }
92
93 // Look in the page title for results count
94 const title = document.title;
95 if (title) {
96 const numbers = title.match(/\d+/g);
97 if (numbers && numbers.length > 0) {
98 return {
99 selector: 'title',
100 numbers: numbers
101 };
102 }
103 }
104
105 // Count the actual result items as fallback
106 const resultItems = document.querySelectorAll('ol li');
107 if (resultItems.length > 0) {
108 return {
109 selector: 'counted-items',
110 numbers: [resultItems.length.toString()]
111 };
112 }
113
114 return null;
115 });
116
117 if (!resultsInfo || !resultsInfo.numbers || resultsInfo.numbers.length === 0) {
118 // Final fallback: just count visible list items
119 const itemCount = await page.evaluate(() => {
120 return document.querySelectorAll('ol li').length;
121 });
122
123 if (itemCount > 0) {
124 return itemCount;
125 }
126
127 throw new Error("Cannot find any results count on the page");
128 }
129
130 // Extract the largest number found (likely the total results)
131 const hits = Math.max(...resultsInfo.numbers.map(n => parseInt(n, 10)));
Marc Kupietz9e0f5192025-03-09 12:12:16 +0100132 return hits;
Marc Kupietz5e45a2f2022-12-03 15:32:40 +0100133 }
134
135 async logout(page) {
Marc Kupietz964e7772025-06-03 15:02:30 +0200136 try {
137 // Direct navigation to logout URL - most reliable method
138 const currentUrl = await page.url();
139 const logoutUrl = currentUrl.replace(/\/$/, '') + '/logout';
140
141 await page.goto(logoutUrl, { waitUntil: 'domcontentloaded', timeout: 10000 });
142
143 // Navigate back to main page to ensure clean state for subsequent tests
144 await page.goto(this.korap_url, { waitUntil: 'domcontentloaded', timeout: 10000 });
145
146 return true;
147 } catch (error) {
148 return false;
Marc Kupietz5e45a2f2022-12-03 15:32:40 +0100149 }
Marc Kupietz5e45a2f2022-12-03 15:32:40 +0100150 }
151
152 async assure_glimpse_off(page) {
153 const glimpse = await page.$("input[name=cutoff]")
154 const glimpse_value = await (await glimpse.getProperty('checked')).jsonValue()
155 if (glimpse_value) {
156 await page.click("#glimpse")
157 }
Marc Kupietzc8ffb2b2025-06-12 16:44:23 +0200158 }
Marc Kupietz5e45a2f2022-12-03 15:32:40 +0100159
Marc Kupietzc8ffb2b2025-06-12 16:44:23 +0200160 async check_corpus_statistics(page, minTokenThreshold = 1000) {
161 try {
162 // Navigate to the corpus view if not already there
163 await page.goto(this.korap_url, { waitUntil: 'networkidle2' });
164
165 // Click the vc-choose element to open corpus selection
166 await page.waitForSelector('#vc-choose', { visible: true, timeout: 10000 });
167 await page.click('#vc-choose');
168
169 // Wait a moment for the UI to respond
170 await new Promise(resolve => setTimeout(resolve, 1000));
171
172 // Click the statistic element
173 await page.waitForSelector('.statistic', { visible: true, timeout: 10000 });
174 await page.click('.statistic');
175
176 // Wait for statistics to load
177 await new Promise(resolve => setTimeout(resolve, 3000));
178
179 // Look for the tokens count in a dd element that follows an element with title "tokens"
180 const tokenCount = await page.evaluate((minThreshold) => {
181 // Find the element with title "tokens"
182 const tokenTitleElements = document.querySelectorAll('[title="tokens"], [title*="token"]');
183
184 for (const element of tokenTitleElements) {
185 // Look for the next dd element
186 let nextElement = element.nextElementSibling;
187 while (nextElement) {
188 if (nextElement.tagName.toLowerCase() === 'dd') {
189 const text = nextElement.textContent || nextElement.innerText || '';
190 // Remove number separators (commas and periods) and extract number
191 const cleanedText = text.replace(/[,\.]/g, '');
192 const numbers = cleanedText.match(/\d+/g);
193 if (numbers && numbers.length > 0) {
194 return parseInt(numbers[0], 10);
195 }
196 }
197 nextElement = nextElement.nextElementSibling;
198 }
199 }
200
201 // Alternative approach: look for dd elements that contain large numbers
202 const ddElements = document.querySelectorAll('dd');
203 for (const dd of ddElements) {
204 const text = dd.textContent || dd.innerText || '';
205 // Remove separators and check if it's a large number (likely token count)
206 const cleanedText = text.replace(/[,\.]/g, '');
207 const numbers = cleanedText.match(/\d+/g);
208 if (numbers && numbers.length > 0) {
209 const num = parseInt(numbers[0], 10);
210 // Use the provided threshold instead of hardcoded value
211 if (num > minThreshold) {
212 return num;
213 }
214 }
215 }
216
217 return null;
218 }, minTokenThreshold);
219
220 if (tokenCount === null) {
221 throw new Error("Could not find token count in corpus statistics");
222 }
223
224 return tokenCount;
225
226 } catch (error) {
227 throw new Error(`Failed to check corpus statistics: ${error.message}`);
228 }
Marc Kupietz5e45a2f2022-12-03 15:32:40 +0100229 }
230}
231
232module.exports = KorAPRC